Skip to content

Commit

Permalink
Fixed empty senderPublicKey field while asset scritp execution. Fixed…
Browse files Browse the repository at this point in the history
… an issue then half empty TransferScriptAction produced on invalid asset. (#407)
  • Loading branch information
alexeykiselev authored Jan 5, 2021
1 parent 87a4b6a commit fd4135b
Show file tree
Hide file tree
Showing 6 changed files with 173 additions and 26 deletions.
30 changes: 20 additions & 10 deletions cmd/rollback/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,12 @@ import (
)

var (
logLevel = flag.String("log-level", "INFO", "Logging level. Supported levels: DEBUG, INFO, WARN, ERROR, FATAL. Default logging level INFO.")
statePath = flag.String("state-path", "", "Path to node's state directory")
blockchainType = flag.String("blockchain-type", "mainnet", "Blockchain type: mainnet/testnet/stagenet")
height = flag.Uint64("height", 0, "Height to rollback")
logLevel = flag.String("log-level", "INFO", "Logging level. Supported levels: DEBUG, INFO, WARN, ERROR, FATAL. Default logging level INFO.")
statePath = flag.String("state-path", "", "Path to node's state directory")
blockchainType = flag.String("blockchain-type", "mainnet", "Blockchain type: mainnet/testnet/stagenet")
height = flag.Uint64("height", 0, "Height to rollback")
buildExtendedApi = flag.Bool("build-extended-api", false, "Builds extended API. Note that state must be reimported in case it wasn't imported with similar flag set")
buildStateHashes = flag.Bool("build-state-hashes", false, "Calculate and store state hashes for each block height.")
)

func main() {
Expand All @@ -31,31 +33,39 @@ func main() {
return
}
params := state.DefaultStateParams()
state, err := state.NewState(*statePath, params, cfg)
params.BuildStateHashes = *buildStateHashes
params.StoreExtendedApiData = *buildExtendedApi
s, err := state.NewState(*statePath, params, cfg)
if err != nil {
zap.S().Error(err)
return
}
defer func() {
err = s.Close()
if err != nil {
zap.S().Errorf("Failed to close state: %v", err)
}
}()

curHeight, err := state.Height()
curHeight, err := s.Height()
if err != nil {
zap.S().Error(err)
return
}

zap.S().Infof("current height: %d", curHeight)
zap.S().Infof("Current height: %d", curHeight)

err = state.RollbackToHeight(*height)
err = s.RollbackToHeight(*height)
if err != nil {
zap.S().Error(err)
return
}

curHeight, err = state.Height()
curHeight, err = s.Height()
if err != nil {
zap.S().Error(err)
return
}

zap.S().Infof("current height: %d", curHeight)
zap.S().Infof("Current height: %d", curHeight)
}
10 changes: 3 additions & 7 deletions pkg/proto/scripting.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,9 @@ func (a *DataEntryScriptAction) ToProtobuf() *g.DataTransactionData_DataEntry {

// TransferScriptAction is an action to emit transfer of asset.
type TransferScriptAction struct {
Recipient Recipient
Amount int64
Asset OptionalAsset
InvalidAsset bool
Recipient Recipient
Amount int64
Asset OptionalAsset
}

func (a TransferScriptAction) scriptAction() {}
Expand Down Expand Up @@ -332,9 +331,6 @@ func ValidateActions(actions []ScriptAction, restrictions ActionsValidationRestr
if ta.Amount < 0 {
return errors.New("negative transfer amount")
}
if ta.InvalidAsset {
return errors.New("invalid asset")
}
if restrictions.DisableSelfTransfers {
if ta.Recipient.Address.Eq(restrictions.ScriptAddress) {
return errors.New("transfers to DApp itself are forbidden since activation of RIDE V4")
Expand Down
4 changes: 3 additions & 1 deletion pkg/proto/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -3232,16 +3232,18 @@ type FullScriptTransfer struct {
Asset OptionalAsset
Recipient Recipient
Sender Address
SenderPK crypto.PublicKey
Timestamp uint64
ID *crypto.Digest
}

func NewFullScriptTransfer(action *TransferScriptAction, sender Address, tx *InvokeScriptWithProofs) (*FullScriptTransfer, error) {
func NewFullScriptTransfer(action *TransferScriptAction, sender Address, senderPK crypto.PublicKey, tx *InvokeScriptWithProofs) (*FullScriptTransfer, error) {
return &FullScriptTransfer{
Amount: uint64(action.Amount),
Asset: action.Asset,
Recipient: action.Recipient,
Sender: sender,
SenderPK: senderPK,
Timestamp: tx.Timestamp,
ID: tx.ID,
}, nil
Expand Down
19 changes: 12 additions & 7 deletions pkg/ride/converters.go
Original file line number Diff line number Diff line change
Expand Up @@ -956,7 +956,7 @@ func scriptTransferToObject(tr *proto.FullScriptTransfer) rideObject {
r["version"] = rideUnit{}
r["id"] = rideBytes(tr.ID.Bytes())
r["sender"] = rideAddress(tr.Sender)
r["senderPublicKey"] = rideUnit{}
r["senderPublicKey"] = rideBytes(common.Dup(tr.SenderPK.Bytes()))
r["recipient"] = rideRecipient(tr.Recipient)
r["assetId"] = optionalAsset(tr.Asset)
r["amount"] = rideInt(tr.Amount)
Expand Down Expand Up @@ -1211,15 +1211,20 @@ func convertToAction(env RideEnvironment, obj rideType) (proto.ScriptAction, err
return nil, errors.Wrap(err, "failed to convert ScriptTransfer to ScriptAction")
}
asset, err := optionalAssetProperty(obj, "asset")
invalidAsset := false
// On asset ID conversion error we return empty action as in Scala
// See example on MainNet: transaction (https://wavesexplorer.com/tx/AUpiEr49Jo43Q9zXKkNN23rstiq87hguvhfQqV8ov9uQ)
// and script (https://wavesexplorer.com/tx/Bp1oieWHWpLz8vBFZui9tY1oDTAKUPTrBAGcwfRe9q5K)
if err != nil {
invalidAsset = true
return &proto.TransferScriptAction{
Recipient: recipient,
Amount: 0,
Asset: proto.OptionalAsset{Present: false},
}, nil
}
return &proto.TransferScriptAction{
Recipient: recipient,
Amount: int64(amount),
Asset: asset,
InvalidAsset: invalidAsset,
Recipient: recipient,
Amount: int64(amount),
Asset: asset,
}, nil
case "SponsorFee":
id, err := digestProperty(obj, "assetId")
Expand Down
134 changes: 134 additions & 0 deletions pkg/ride/tree_evaluation_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3381,3 +3381,137 @@ func TestRecipientAddressToString(t *testing.T) {
require.True(t, ok)
assert.True(t, r.Result())
}

func TestScriptPaymentPublicKey(t *testing.T) {
pk := crypto.MustPublicKeyFromBase58("7gYTeHxHZ2NRQdNpa6DHAxQY4K5LS6bezcsMQcUhYuo1")
addr := proto.MustAddressFromPublicKey(proto.MainNetScheme, pk)
asset, err := proto.NewOptionalAssetFromString("5F4PshPwzE8sQeesDPzjJN45CFVnAnqCUHJcmi7kZq22")
require.NoError(t, err)
rcp := proto.NewRecipientFromAddress(addr)
action := &proto.TransferScriptAction{
Recipient: rcp,
Amount: 12345,
Asset: *asset,
}
id := crypto.MustDigestFromBase58("9vt45R9y63Xwcseat59BchUjfJGHSuN5LeTK6Pd6cFUM")
tx := &proto.InvokeScriptWithProofs{
Type: proto.InvokeScriptTransaction,
Version: 1,
ID: &id,
ChainID: proto.MainNetScheme,
SenderPK: pk,
ScriptRecipient: rcp,
Payments: proto.ScriptPayments{},
FeeAsset: proto.OptionalAsset{},
Fee: 1300000,
Timestamp: 1599565088614,
}

tr, _ := proto.NewFullScriptTransfer(action, addr, pk, tx)
env := &MockRideEnvironment{
schemeFunc: func() byte {
return proto.MainNetScheme
},
transactionFunc: func() rideObject {
return scriptTransferToObject(tr)
},
checkMessageLengthFunc: v3check,
}

code := "AQQAAAAGc2VuZGVyCQACWAAAAAEICQEAAAAUYWRkcmVzc0Zyb21QdWJsaWNLZXkAAAABCAUAAAACdHgAAAAPc2VuZGVyUHVibGljS2V5AAAABWJ5dGVzCQAAAAAAAAICAAAAIzNQNjFiNnRlMmZ2akw3YWdLSHFOY0NrcHV0Z1lzNjV4dzVSBQAAAAZzZW5kZXJlKXM0"
src, err := base64.StdEncoding.DecodeString(code)
require.NoError(t, err)
tree, err := Parse(src)
require.NoError(t, err)
assert.NotNil(t, tree)

res, err := CallVerifier(env, tree)
require.NoError(t, err)
r, ok := res.(ScriptResult)
require.True(t, ok)
require.True(t, r.Result())
}

func TestInvalidAssetInTransferScriptAction(t *testing.T) {
txID, err := crypto.NewDigestFromBase58("AUpiEr49Jo43Q9zXKkNN23rstiq87hguvhfQqV8ov9uQ")
require.NoError(t, err)
proofs := proto.NewProofs()
sender, err := crypto.NewPublicKeyFromBase58("Hjd6p3ArqjnQAsejFwu7JcQciVVx9RaQhtMfGBCAi76z")
require.NoError(t, err)
address, err := proto.NewAddressFromString("3P8FF73N7ZvvNJ34vnJ3h9Tfmh7oQCnRz8E")
require.NoError(t, err)
recipient := proto.NewRecipientFromAddress(address)
arguments := proto.Arguments{}
call := proto.FunctionCall{
Default: false,
Name: "swapRKMTToWAVES",
Arguments: arguments,
}
asset, err := proto.NewOptionalAssetFromString("2fCdmsn6maErwtLuzxoUrCBkh2vx5SvXtMKAJtN4YBgd")
require.NoError(t, err)
tx := &proto.InvokeScriptWithProofs{
Type: proto.InvokeScriptTransaction,
Version: 1,
ID: &txID,
Proofs: proofs,
ChainID: proto.MainNetScheme,
SenderPK: sender,
ScriptRecipient: recipient,
FunctionCall: call,
Payments: proto.ScriptPayments{proto.ScriptPayment{Amount: 1000, Asset: *asset}},
FeeAsset: proto.OptionalAsset{},
Fee: 500000,
Timestamp: 1609698441420,
}
env := &MockRideEnvironment{
schemeFunc: func() byte {
return proto.MainNetScheme
},
thisFunc: func() rideType {
return rideAddress(address)
},
transactionFunc: func() rideObject {
obj, err := transactionToObject(proto.MainNetScheme, tx)
require.NoError(t, err)
return obj
},
invocationFunc: func() rideObject {
obj, err := invocationToObject(3, proto.MainNetScheme, tx)
require.NoError(t, err)
return obj
},
checkMessageLengthFunc: v3check,
}

code := "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"
src, err := base64.StdEncoding.DecodeString(code)
require.NoError(t, err)
tree, err := Parse(src)
require.NoError(t, err)
assert.NotNil(t, tree)
res, err := CallFunction(env, tree, "swapRKMTToWAVES", arguments)
require.NoError(t, err)
r, ok := res.(DAppResult)
require.True(t, ok)
require.True(t, r.res)

sr, err := proto.NewScriptResult(r.actions, proto.ScriptErrorMessage{})
require.NoError(t, err)

expectedTransfers := []*proto.TransferScriptAction{
{
Recipient: proto.NewRecipientFromAddress(proto.MustAddressFromString("3P8FF73N7ZvvNJ34vnJ3h9Tfmh7oQCnRz8E")),
Amount: 0,
Asset: proto.OptionalAsset{Present: false},
},
}
expectedResult := &proto.ScriptResult{
DataEntries: make([]*proto.DataEntryScriptAction, 0),
Transfers: expectedTransfers,
Issues: make([]*proto.IssueScriptAction, 0),
Reissues: make([]*proto.ReissueScriptAction, 0),
Burns: make([]*proto.BurnScriptAction, 0),
Sponsorships: make([]*proto.SponsorshipScriptAction, 0),
}
assert.Equal(t, expectedResult, sr)
}
2 changes: 1 addition & 1 deletion pkg/state/invoke_applier.go
Original file line number Diff line number Diff line change
Expand Up @@ -303,7 +303,7 @@ func (ia *invokeApplier) fallibleValidation(tx *proto.InvokeScriptWithProofs, in
}
sender = addr
}
fullTr, err := proto.NewFullScriptTransfer(a, *sender, tx)
fullTr, err := proto.NewFullScriptTransfer(a, *sender, info.scriptPK, tx)
if err != nil {
return proto.DAppError, info.failedChanges, errors.Wrap(err, "failed to convert transfer to full script transfer")
}
Expand Down

0 comments on commit fd4135b

Please sign in to comment.