diff --git a/integration/performance_test.go b/integration/performance_test.go index f2768c68b..d5e80e03b 100644 --- a/integration/performance_test.go +++ b/integration/performance_test.go @@ -79,16 +79,12 @@ func getTX(t *testing.B, wif *keys.WIF) *transaction.Transaction { tx := transaction.NewInvocationTX([]byte{0x51}, 1) tx.Version = 0 + tx.Sender = fromAddressHash tx.Attributes = append(tx.Attributes, transaction.Attribute{ Usage: transaction.Description, Data: []byte(randString(10)), }) - tx.Attributes = append(tx.Attributes, - transaction.Attribute{ - Usage: transaction.Script, - Data: fromAddressHash.BytesBE(), - }) return tx } diff --git a/pkg/core/blockchain.go b/pkg/core/blockchain.go index 01b7b6dd8..ce6e19c2d 100644 --- a/pkg/core/blockchain.go +++ b/pkg/core/blockchain.go @@ -1548,17 +1548,6 @@ func (bc *Blockchain) GetScriptHashesForVerifying(t *transaction.Transaction) ([ for i := range references { hashes[references[i].Out.ScriptHash] = true } - for _, a := range t.Attributes { - if a.Usage == transaction.Script { - h, err := util.Uint160DecodeBytesBE(a.Data) - if err != nil { - return nil, err - } - if _, ok := hashes[h]; !ok { - hashes[h] = true - } - } - } for a, outputs := range t.GroupOutputByAssetID() { as := bc.GetAssetState(a) @@ -1575,6 +1564,9 @@ func (bc *Blockchain) GetScriptHashesForVerifying(t *transaction.Transaction) ([ } } hashes[t.Sender] = true + for _, c := range t.Cosigners { + hashes[c.Account] = true + } switch t.Type { case transaction.ClaimType: claim := t.Data.(*transaction.ClaimTX) diff --git a/pkg/core/interop/runtime/witness.go b/pkg/core/interop/runtime/witness.go index 1f1dd58f6..094737bef 100644 --- a/pkg/core/interop/runtime/witness.go +++ b/pkg/core/interop/runtime/witness.go @@ -2,6 +2,7 @@ package runtime import ( "github.com/nspcc-dev/neo-go/pkg/core/interop" + "github.com/nspcc-dev/neo-go/pkg/core/transaction" "github.com/nspcc-dev/neo-go/pkg/crypto/keys" "github.com/nspcc-dev/neo-go/pkg/util" "github.com/nspcc-dev/neo-go/pkg/vm" @@ -10,7 +11,12 @@ import ( // CheckHashedWitness checks given hash against current list of script hashes // for verifying in the interop context. -func CheckHashedWitness(ic *interop.Context, hash util.Uint160) (bool, error) { +func CheckHashedWitness(ic *interop.Context, v vm.ScriptHashGetter, hash util.Uint160) (bool, error) { + if tx, ok := ic.Container.(*transaction.Transaction); ok { + return checkScope(tx, v, hash) + } + + // only for non-Transaction types (Block, etc.) hashes, err := ic.Chain.GetScriptHashesForVerifying(ic.Tx) if err != nil { return false, errors.Wrap(err, "failed to get script hashes") @@ -23,10 +29,57 @@ func CheckHashedWitness(ic *interop.Context, hash util.Uint160) (bool, error) { return false, nil } +func checkScope(tx *transaction.Transaction, v vm.ScriptHashGetter, hash util.Uint160) (bool, error) { + for _, c := range tx.Cosigners { + if c.Account == hash { + if c.Scopes == transaction.Global { + return true, nil + } + if c.Scopes&transaction.CalledByEntry != 0 { + callingScriptHash := v.GetCallingScriptHash() + entryScriptHash := v.GetEntryScriptHash() + if callingScriptHash == entryScriptHash { + return true, nil + } + } + if c.Scopes&transaction.CustomContracts != 0 { + currentScriptHash := v.GetCurrentScriptHash() + for _, allowedContract := range c.AllowedContracts { + if allowedContract == currentScriptHash { + return true, nil + } + } + } + if c.Scopes&transaction.CustomGroups != 0 { + return true, nil + // TODO: we don't currently have Manifest field in ContractState + /*callingScriptHash := v.GetCallingScriptHash() + if callingScriptHash.Equals(util.Uint160{}){ + return false, nil + } + cs, err := ic.DAO.GetContractState(callingScriptHash) + if err != nil { + return false, err + } + // check if the current group is the required one + for _, allowedGroup := range c.AllowedGroups { + for _, group := range cs.Manifest.Groups { + if group.PublicKey.Equal(allowedGroup) { + return true, nil + } + } + }*/ + } + return false, nil + } + } + return false, nil +} + // CheckKeyedWitness checks hash of signature check contract with a given public // key against current list of script hashes for verifying in the interop context. -func CheckKeyedWitness(ic *interop.Context, key *keys.PublicKey) (bool, error) { - return CheckHashedWitness(ic, key.GetScriptHash()) +func CheckKeyedWitness(ic *interop.Context, v vm.ScriptHashGetter, key *keys.PublicKey) (bool, error) { + return CheckHashedWitness(ic, v, key.GetScriptHash()) } // CheckWitness checks witnesses. @@ -42,9 +95,9 @@ func CheckWitness(ic *interop.Context, v *vm.VM) error { if err != nil { return errors.New("parameter given is neither a key nor a hash") } - res, err = CheckKeyedWitness(ic, key) + res, err = CheckKeyedWitness(ic, v, key) } else { - res, err = CheckHashedWitness(ic, hash) + res, err = CheckHashedWitness(ic, v, hash) } if err != nil { return errors.Wrap(err, "failed to check") diff --git a/pkg/core/interop_neo.go b/pkg/core/interop_neo.go index 6dcc1f9b9..0507764dc 100644 --- a/pkg/core/interop_neo.go +++ b/pkg/core/interop_neo.go @@ -540,7 +540,7 @@ func contractMigrate(ic *interop.Context, v *vm.VM) error { return err } if contract.HasStorage() { - hash := v.GetContextScriptHash(0) + hash := v.GetCurrentScriptHash() siMap, err := ic.DAO.GetStorageItems(hash) if err != nil { return err @@ -601,7 +601,7 @@ func assetCreate(ic *interop.Context, v *vm.VM) error { if owner.IsInfinity() { return errors.New("can't have infinity as an owner key") } - witnessOk, err := runtime.CheckKeyedWitness(ic, owner) + witnessOk, err := runtime.CheckKeyedWitness(ic, v, owner) if err != nil { return err } diff --git a/pkg/core/interop_system.go b/pkg/core/interop_system.go index 396534c8a..30f085f7c 100644 --- a/pkg/core/interop_system.go +++ b/pkg/core/interop_system.go @@ -292,7 +292,7 @@ func runtimeNotify(ic *interop.Context, v *vm.VM) error { if err != nil { item = vm.NewByteArrayItem([]byte(fmt.Sprintf("bad notification: %v", err))) } - ne := state.NotificationEvent{ScriptHash: v.GetContextScriptHash(0), Item: item} + ne := state.NotificationEvent{ScriptHash: v.GetCurrentScriptHash(), Item: item} ic.Notifications = append(ic.Notifications, ne) return nil } @@ -301,7 +301,7 @@ func runtimeNotify(ic *interop.Context, v *vm.VM) error { func runtimeLog(ic *interop.Context, v *vm.VM) error { msg := fmt.Sprintf("%q", v.Estack().Pop().Bytes()) ic.Log.Info("runtime log", - zap.Stringer("script", v.GetContextScriptHash(0)), + zap.Stringer("script", v.GetCurrentScriptHash()), zap.String("logs", msg)) return nil } @@ -383,7 +383,7 @@ func storageGet(ic *interop.Context, v *vm.VM) error { // storageGetContext returns storage context (scripthash). func storageGetContext(ic *interop.Context, v *vm.VM) error { sc := &StorageContext{ - ScriptHash: v.GetContextScriptHash(0), + ScriptHash: v.GetCurrentScriptHash(), ReadOnly: false, } v.Estack().PushVal(vm.NewInteropItem(sc)) @@ -393,7 +393,7 @@ func storageGetContext(ic *interop.Context, v *vm.VM) error { // storageGetReadOnlyContext returns read-only context (scripthash). func storageGetReadOnlyContext(ic *interop.Context, v *vm.VM) error { sc := &StorageContext{ - ScriptHash: v.GetContextScriptHash(0), + ScriptHash: v.GetCurrentScriptHash(), ReadOnly: true, } v.Estack().PushVal(vm.NewInteropItem(sc)) @@ -475,7 +475,7 @@ func contractDestroy(ic *interop.Context, v *vm.VM) error { if ic.Trigger != trigger.Application { return errors.New("can't destroy contract when not triggered by application") } - hash := v.GetContextScriptHash(0) + hash := v.GetCurrentScriptHash() cs, err := ic.DAO.GetContractState(hash) if err != nil { return nil diff --git a/pkg/core/native/contract.go b/pkg/core/native/contract.go index a4b83e751..a16df5af8 100644 --- a/pkg/core/native/contract.go +++ b/pkg/core/native/contract.go @@ -69,7 +69,7 @@ func (cs *Contracts) GetNativeInterop(ic *interop.Context) func(uint32) *vm.Inte // getNativeInterop returns native contract interop. func getNativeInterop(ic *interop.Context, c interop.Contract) func(v *vm.VM) error { return func(v *vm.VM) error { - h := v.GetContextScriptHash(0) + h := v.GetCurrentScriptHash() if !h.Equals(c.Metadata().Hash) { return errors.New("invalid hash") } diff --git a/pkg/core/native/native_neo.go b/pkg/core/native/native_neo.go index f159b18ad..cd35e942a 100644 --- a/pkg/core/native/native_neo.go +++ b/pkg/core/native/native_neo.go @@ -251,7 +251,7 @@ func (n *NEO) vote(ic *interop.Context, args []vm.StackItem) vm.StackItem { // VoteInternal votes from account h for validarors specified in pubs. func (n *NEO) VoteInternal(ic *interop.Context, h util.Uint160, pubs keys.PublicKeys) error { - ok, err := runtime.CheckHashedWitness(ic, h) + ok, err := runtime.CheckHashedWitness(ic, neoScriptHash{hash: n.Hash}, h) if err != nil { return err } else if !ok { @@ -479,3 +479,24 @@ func toPublicKey(s vm.StackItem) *keys.PublicKey { } return pub } + +// scriptHash is an auxiliary structure which implements ScriptHashGetter +// interface over NEO native contract and is used for runtime.CheckHashedWitness +type neoScriptHash struct { + hash util.Uint160 +} + +// GetCallingScriptHash implements ScriptHashGetter interface +func (s neoScriptHash) GetCallingScriptHash() util.Uint160 { + return util.Uint160{} +} + +// GetEntryScriptHash implements ScriptHashGetter interface +func (s neoScriptHash) GetEntryScriptHash() util.Uint160 { + return s.hash +} + +// GetCurrentScriptHash implements ScriptHashGetter interface +func (s neoScriptHash) GetCurrentScriptHash() util.Uint160 { + return s.hash +} diff --git a/pkg/core/state/account.go b/pkg/core/state/account.go index 2fc3a4f66..4e65ec27e 100644 --- a/pkg/core/state/account.go +++ b/pkg/core/state/account.go @@ -49,7 +49,7 @@ func NewAccount(scriptHash util.Uint160) *Account { // DecodeBinary decodes Account from the given BinReader. func (s *Account) DecodeBinary(br *io.BinReader) { s.Version = uint8(br.ReadB()) - br.ReadBytes(s.ScriptHash[:]) + s.ScriptHash.DecodeBinary(br) s.IsFrozen = br.ReadBool() s.Balances = make(map[util.Uint256][]UnspentBalance) @@ -73,7 +73,7 @@ func (s *Account) DecodeBinary(br *io.BinReader) { // EncodeBinary encodes Account to the given BinWriter. func (s *Account) EncodeBinary(bw *io.BinWriter) { bw.WriteB(byte(s.Version)) - bw.WriteBytes(s.ScriptHash[:]) + s.ScriptHash.EncodeBinary(bw) bw.WriteBool(s.IsFrozen) bw.WriteVarUint(uint64(len(s.Balances))) diff --git a/pkg/core/state/asset.go b/pkg/core/state/asset.go index 0b624516b..d59deba68 100644 --- a/pkg/core/state/asset.go +++ b/pkg/core/state/asset.go @@ -37,11 +37,11 @@ func (a *Asset) DecodeBinary(br *io.BinReader) { a.Available.DecodeBinary(br) a.Precision = uint8(br.ReadB()) a.FeeMode = uint8(br.ReadB()) - br.ReadBytes(a.FeeAddress[:]) + a.FeeAddress.DecodeBinary(br) a.Owner.DecodeBinary(br) - br.ReadBytes(a.Admin[:]) - br.ReadBytes(a.Issuer[:]) + a.Admin.DecodeBinary(br) + a.Issuer.DecodeBinary(br) a.Expiration = br.ReadU32LE() a.IsFrozen = br.ReadBool() } @@ -55,12 +55,12 @@ func (a *Asset) EncodeBinary(bw *io.BinWriter) { a.Available.EncodeBinary(bw) bw.WriteB(byte(a.Precision)) bw.WriteB(byte(a.FeeMode)) - bw.WriteBytes(a.FeeAddress[:]) + a.FeeAddress.EncodeBinary(bw) a.Owner.EncodeBinary(bw) - bw.WriteBytes(a.Admin[:]) - bw.WriteBytes(a.Issuer[:]) + a.Admin.EncodeBinary(bw) + a.Issuer.EncodeBinary(bw) bw.WriteU32LE(a.Expiration) bw.WriteBool(a.IsFrozen) } diff --git a/pkg/core/state/notification_event.go b/pkg/core/state/notification_event.go index 2599f781e..06e634464 100644 --- a/pkg/core/state/notification_event.go +++ b/pkg/core/state/notification_event.go @@ -28,13 +28,13 @@ type AppExecResult struct { // EncodeBinary implements the Serializable interface. func (ne *NotificationEvent) EncodeBinary(w *io.BinWriter) { - w.WriteBytes(ne.ScriptHash[:]) + ne.ScriptHash.EncodeBinary(w) vm.EncodeBinaryStackItem(ne.Item, w) } // DecodeBinary implements the Serializable interface. func (ne *NotificationEvent) DecodeBinary(r *io.BinReader) { - r.ReadBytes(ne.ScriptHash[:]) + ne.ScriptHash.DecodeBinary(r) ne.Item = vm.DecodeBinaryStackItem(r) } diff --git a/pkg/core/transaction/attr_usage.go b/pkg/core/transaction/attr_usage.go index c9f8db22e..f430d32f0 100644 --- a/pkg/core/transaction/attr_usage.go +++ b/pkg/core/transaction/attr_usage.go @@ -10,7 +10,6 @@ const ( ContractHash AttrUsage = 0x00 ECDH02 AttrUsage = 0x02 ECDH03 AttrUsage = 0x03 - Script AttrUsage = 0x20 Vote AttrUsage = 0x30 CertURL AttrUsage = 0x80 DescriptionURL AttrUsage = 0x81 diff --git a/pkg/core/transaction/attribute.go b/pkg/core/transaction/attribute.go index ca4a0ed28..66fe97cb4 100644 --- a/pkg/core/transaction/attribute.go +++ b/pkg/core/transaction/attribute.go @@ -31,8 +31,6 @@ func (attr *Attribute) DecodeBinary(br *io.BinReader) { Hash6, Hash7, Hash8, Hash9, Hash10, Hash11, Hash12, Hash13, Hash14, Hash15: datasize = 32 - case Script: - datasize = 20 case DescriptionURL: // It's not VarUint as per C# implementation, dunno why var urllen = br.ReadB() @@ -62,7 +60,7 @@ func (attr *Attribute) EncodeBinary(bw *io.BinWriter) { case DescriptionURL: bw.WriteB(byte(len(attr.Data))) fallthrough - case Script, ContractHash, Vote, Hash1, Hash2, Hash3, Hash4, Hash5, Hash6, + case ContractHash, Vote, Hash1, Hash2, Hash3, Hash4, Hash5, Hash6, Hash7, Hash8, Hash9, Hash10, Hash11, Hash12, Hash13, Hash14, Hash15: bw.WriteBytes(attr.Data) default: diff --git a/pkg/core/transaction/attrusage_string.go b/pkg/core/transaction/attrusage_string.go index c0da95199..b63e1840e 100644 --- a/pkg/core/transaction/attrusage_string.go +++ b/pkg/core/transaction/attrusage_string.go @@ -11,7 +11,6 @@ func _() { _ = x[ContractHash-0] _ = x[ECDH02-2] _ = x[ECDH03-3] - _ = x[Script-32] _ = x[Vote-48] _ = x[CertURL-128] _ = x[DescriptionURL-129] @@ -52,19 +51,18 @@ func _() { const ( _AttrUsage_name_0 = "ContractHash" _AttrUsage_name_1 = "ECDH02ECDH03" - _AttrUsage_name_2 = "Script" - _AttrUsage_name_3 = "Vote" - _AttrUsage_name_4 = "CertURLDescriptionURL" - _AttrUsage_name_5 = "Description" - _AttrUsage_name_6 = "Hash1Hash2Hash3Hash4Hash5Hash6Hash7Hash8Hash9Hash10Hash11Hash12Hash13Hash14Hash15" - _AttrUsage_name_7 = "RemarkRemark1Remark2Remark3Remark4Remark5Remark6Remark7Remark8Remark9Remark10Remark11Remark12Remark13Remark14Remark15" + _AttrUsage_name_2 = "Vote" + _AttrUsage_name_3 = "CertURLDescriptionURL" + _AttrUsage_name_4 = "Description" + _AttrUsage_name_5 = "Hash1Hash2Hash3Hash4Hash5Hash6Hash7Hash8Hash9Hash10Hash11Hash12Hash13Hash14Hash15" + _AttrUsage_name_6 = "RemarkRemark1Remark2Remark3Remark4Remark5Remark6Remark7Remark8Remark9Remark10Remark11Remark12Remark13Remark14Remark15" ) var ( _AttrUsage_index_1 = [...]uint8{0, 6, 12} - _AttrUsage_index_4 = [...]uint8{0, 7, 21} - _AttrUsage_index_6 = [...]uint8{0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 51, 57, 63, 69, 75, 81} - _AttrUsage_index_7 = [...]uint8{0, 6, 13, 20, 27, 34, 41, 48, 55, 62, 69, 77, 85, 93, 101, 109, 117} + _AttrUsage_index_3 = [...]uint8{0, 7, 21} + _AttrUsage_index_5 = [...]uint8{0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 51, 57, 63, 69, 75, 81} + _AttrUsage_index_6 = [...]uint8{0, 6, 13, 20, 27, 34, 41, 48, 55, 62, 69, 77, 85, 93, 101, 109, 117} ) func (i AttrUsage) String() string { @@ -74,21 +72,19 @@ func (i AttrUsage) String() string { case 2 <= i && i <= 3: i -= 2 return _AttrUsage_name_1[_AttrUsage_index_1[i]:_AttrUsage_index_1[i+1]] - case i == 32: - return _AttrUsage_name_2 case i == 48: - return _AttrUsage_name_3 + return _AttrUsage_name_2 case 128 <= i && i <= 129: i -= 128 - return _AttrUsage_name_4[_AttrUsage_index_4[i]:_AttrUsage_index_4[i+1]] + return _AttrUsage_name_3[_AttrUsage_index_3[i]:_AttrUsage_index_3[i+1]] case i == 144: - return _AttrUsage_name_5 + return _AttrUsage_name_4 case 161 <= i && i <= 175: i -= 161 - return _AttrUsage_name_6[_AttrUsage_index_6[i]:_AttrUsage_index_6[i+1]] + return _AttrUsage_name_5[_AttrUsage_index_5[i]:_AttrUsage_index_5[i+1]] case 240 <= i && i <= 255: i -= 240 - return _AttrUsage_name_7[_AttrUsage_index_7[i]:_AttrUsage_index_7[i+1]] + return _AttrUsage_name_6[_AttrUsage_index_6[i]:_AttrUsage_index_6[i+1]] default: return "AttrUsage(" + strconv.FormatInt(int64(i), 10) + ")" } diff --git a/pkg/core/transaction/claim.go b/pkg/core/transaction/claim.go index 67cb2f3a0..704d9035b 100644 --- a/pkg/core/transaction/claim.go +++ b/pkg/core/transaction/claim.go @@ -19,6 +19,7 @@ func NewClaimTX(claim *ClaimTX) *Transaction { Nonce: rand.Uint32(), Data: claim, Attributes: []Attribute{}, + Cosigners: []Cosigner{}, Inputs: []Input{}, Outputs: []Output{}, Scripts: []Witness{}, diff --git a/pkg/core/transaction/contract.go b/pkg/core/transaction/contract.go index 09b6a9063..c4a99a1cf 100644 --- a/pkg/core/transaction/contract.go +++ b/pkg/core/transaction/contract.go @@ -18,6 +18,7 @@ func NewContractTX() *Transaction { Nonce: rand.Uint32(), Data: &ContractTX{}, Attributes: []Attribute{}, + Cosigners: []Cosigner{}, Inputs: []Input{}, Outputs: []Output{}, Scripts: []Witness{}, diff --git a/pkg/core/transaction/cosigner.go b/pkg/core/transaction/cosigner.go new file mode 100644 index 000000000..4dbe8a4fa --- /dev/null +++ b/pkg/core/transaction/cosigner.go @@ -0,0 +1,42 @@ +package transaction + +import ( + "github.com/nspcc-dev/neo-go/pkg/crypto/keys" + "github.com/nspcc-dev/neo-go/pkg/io" + "github.com/nspcc-dev/neo-go/pkg/util" +) + +// The maximum number of AllowedContracts or AllowedGroups +const maxSubitems = 16 + +// Cosigner implements a Transaction cosigner. +type Cosigner struct { + Account util.Uint160 `json:"account"` + Scopes WitnessScope `json:"scopes"` + AllowedContracts []util.Uint160 `json:"allowedContracts,omitempty"` + AllowedGroups []*keys.PublicKey `json:"allowedGroups,omitempty"` +} + +// EncodeBinary implements Serializable interface. +func (c *Cosigner) EncodeBinary(bw *io.BinWriter) { + bw.WriteBytes(c.Account[:]) + bw.WriteB(byte(c.Scopes)) + if c.Scopes&CustomContracts != 0 { + bw.WriteArray(c.AllowedContracts) + } + if c.Scopes&CustomGroups != 0 { + bw.WriteArray(c.AllowedGroups) + } +} + +// DecodeBinary implements Serializable interface. +func (c *Cosigner) DecodeBinary(br *io.BinReader) { + br.ReadBytes(c.Account[:]) + c.Scopes = WitnessScope(br.ReadB()) + if c.Scopes&CustomContracts != 0 { + br.ReadArray(&c.AllowedContracts, maxSubitems) + } + if c.Scopes&CustomGroups != 0 { + br.ReadArray(&c.AllowedGroups, maxSubitems) + } +} diff --git a/pkg/core/transaction/cosigner_test.go b/pkg/core/transaction/cosigner_test.go new file mode 100644 index 000000000..a8789f0b9 --- /dev/null +++ b/pkg/core/transaction/cosigner_test.go @@ -0,0 +1,28 @@ +package transaction + +import ( + "testing" + + "github.com/nspcc-dev/neo-go/pkg/internal/testserdes" + "github.com/nspcc-dev/neo-go/pkg/util" +) + +func TestCosignerEncodeDecode(t *testing.T) { + expected := &Cosigner{ + Account: util.Uint160{1, 2, 3, 4, 5}, + Scopes: CustomContracts, + AllowedContracts: []util.Uint160{{1, 2, 3, 4}, {6, 7, 8, 9}}, + } + actual := &Cosigner{} + testserdes.EncodeDecodeBinary(t, expected, actual) +} + +func TestCosignerMarshallUnmarshallJSON(t *testing.T) { + expected := &Cosigner{ + Account: util.Uint160{1, 2, 3, 4, 5}, + Scopes: CustomContracts, + AllowedContracts: []util.Uint160{{1, 2, 3, 4}, {6, 7, 8, 9}}, + } + actual := &Cosigner{} + testserdes.MarshalUnmarshalJSON(t, expected, actual) +} diff --git a/pkg/core/transaction/invocation.go b/pkg/core/transaction/invocation.go index 2b934c772..9abb7b1a9 100644 --- a/pkg/core/transaction/invocation.go +++ b/pkg/core/transaction/invocation.go @@ -31,6 +31,7 @@ func NewInvocationTX(script []byte, gas util.Fixed8) *Transaction { Version: 1, }, Attributes: []Attribute{}, + Cosigners: []Cosigner{}, Inputs: []Input{}, Outputs: []Output{}, Scripts: []Witness{}, diff --git a/pkg/core/transaction/issue.go b/pkg/core/transaction/issue.go index 151d96af7..d2ab6034f 100644 --- a/pkg/core/transaction/issue.go +++ b/pkg/core/transaction/issue.go @@ -18,6 +18,7 @@ func NewIssueTX() *Transaction { Nonce: rand.Uint32(), Data: &IssueTX{}, Attributes: []Attribute{}, + Cosigners: []Cosigner{}, Inputs: []Input{}, Outputs: []Output{}, Scripts: []Witness{}, diff --git a/pkg/core/transaction/register.go b/pkg/core/transaction/register.go index 0351b040d..9bff3efbe 100644 --- a/pkg/core/transaction/register.go +++ b/pkg/core/transaction/register.go @@ -39,6 +39,7 @@ func NewRegisterTX(register *RegisterTX) *Transaction { Nonce: rand.Uint32(), Data: register, Attributes: []Attribute{}, + Cosigners: []Cosigner{}, Inputs: []Input{}, Outputs: []Output{}, Scripts: []Witness{}, @@ -57,7 +58,7 @@ func (tx *RegisterTX) DecodeBinary(br *io.BinReader) { tx.Owner.DecodeBinary(br) - br.ReadBytes(tx.Admin[:]) + tx.Admin.DecodeBinary(br) } // EncodeBinary implements Serializable interface. @@ -67,7 +68,7 @@ func (tx *RegisterTX) EncodeBinary(bw *io.BinWriter) { tx.Amount.EncodeBinary(bw) bw.WriteB(byte(tx.Precision)) bw.WriteBytes(tx.Owner.Bytes()) - bw.WriteBytes(tx.Admin[:]) + tx.Admin.EncodeBinary(bw) } // registeredAsset is a wrapper for RegisterTransaction diff --git a/pkg/core/transaction/transaction.go b/pkg/core/transaction/transaction.go index 160270ed2..e2e399c2a 100644 --- a/pkg/core/transaction/transaction.go +++ b/pkg/core/transaction/transaction.go @@ -19,6 +19,9 @@ const ( // MaxValidUntilBlockIncrement is the upper increment size of blockhain height in blocs after // exceeding that a transaction should fail validation. It is set to be 2102400. MaxValidUntilBlockIncrement = 2102400 + // MaxCosigners is maximum number of cosigners that can be contained within a transaction. + // It is set to be 16. + MaxCosigners = 16 ) // Transaction is a process recorded in the NEO blockchain. @@ -46,6 +49,9 @@ type Transaction struct { // Transaction attributes. Attributes []Attribute + // Transaction cosigners (not include Sender). + Cosigners []Cosigner + // The inputs of the transaction. Inputs []Input @@ -107,25 +113,28 @@ func (t *Transaction) AddInput(in *Input) { t.Inputs = append(t.Inputs, *in) } -// AddVerificationHash adds a script attribute for transaction verification. -func (t *Transaction) AddVerificationHash(addr util.Uint160) { - t.Attributes = append(t.Attributes, Attribute{ - Usage: Script, - Data: addr.BytesBE(), - }) -} - // DecodeBinary implements Serializable interface. func (t *Transaction) DecodeBinary(br *io.BinReader) { t.Type = TXType(br.ReadB()) t.Version = uint8(br.ReadB()) t.Nonce = br.ReadU32LE() - br.ReadBytes(t.Sender[:]) + t.Sender.DecodeBinary(br) t.ValidUntilBlock = br.ReadU32LE() t.decodeData(br) br.ReadArray(&t.Attributes) + + br.ReadArray(&t.Cosigners, MaxCosigners) + for i := 0; i < len(t.Cosigners); i++ { + for j := i + 1; j < len(t.Cosigners); j++ { + if t.Cosigners[i].Account.Equals(t.Cosigners[j].Account) { + br.Err = errors.New("transaction cosigners should be unique") + return + } + } + } + br.ReadArray(&t.Inputs) br.ReadArray(&t.Outputs) for i := range t.Outputs { @@ -182,7 +191,7 @@ func (t *Transaction) encodeHashableFields(bw *io.BinWriter) { bw.WriteB(byte(t.Type)) bw.WriteB(byte(t.Version)) bw.WriteU32LE(t.Nonce) - bw.WriteBytes(t.Sender[:]) + t.Sender.EncodeBinary(bw) bw.WriteU32LE(t.ValidUntilBlock) // Underlying TXer. @@ -193,6 +202,9 @@ func (t *Transaction) encodeHashableFields(bw *io.BinWriter) { // Attributes bw.WriteArray(t.Attributes) + // Cosigners + bw.WriteArray(t.Cosigners) + // Inputs bw.WriteArray(t.Inputs) @@ -267,6 +279,7 @@ type transactionJSON struct { Sender string `json:"sender"` ValidUntilBlock uint32 `json:"valid_until_block"` Attributes []Attribute `json:"attributes"` + Cosigners []Cosigner `json:"cosigners"` Inputs []Input `json:"vin"` Outputs []Output `json:"vout"` Scripts []Witness `json:"scripts"` @@ -288,6 +301,7 @@ func (t *Transaction) MarshalJSON() ([]byte, error) { Sender: address.Uint160ToString(t.Sender), ValidUntilBlock: t.ValidUntilBlock, Attributes: t.Attributes, + Cosigners: t.Cosigners, Inputs: t.Inputs, Outputs: t.Outputs, Scripts: t.Scripts, @@ -323,6 +337,7 @@ func (t *Transaction) UnmarshalJSON(data []byte) error { t.Nonce = tx.Nonce t.ValidUntilBlock = tx.ValidUntilBlock t.Attributes = tx.Attributes + t.Cosigners = tx.Cosigners t.Inputs = tx.Inputs t.Outputs = tx.Outputs t.Scripts = tx.Scripts diff --git a/pkg/core/transaction/witness_scope.go b/pkg/core/transaction/witness_scope.go new file mode 100644 index 000000000..751347148 --- /dev/null +++ b/pkg/core/transaction/witness_scope.go @@ -0,0 +1,19 @@ +package transaction + +// WitnessScope represents set of witness flags for Transaction cosigner. +type WitnessScope byte + +const ( + // Global allows this witness in all contexts (default Neo2 behavior). + // This cannot be combined with other flags. + Global WitnessScope = 0x00 + // CalledByEntry means that this condition must hold: EntryScriptHash == CallingScriptHash. + // No params is needed, as the witness/permission/signature given on first invocation will + // automatically expire if entering deeper internal invokes. This can be default safe + // choice for native NEO/GAS (previously used on Neo 2 as "attach" mode). + CalledByEntry WitnessScope = 0x01 + // CustomContracts define custom hash for contract-specific. + CustomContracts WitnessScope = 0x10 + // CustomGroups define custom pubkey for group members. + CustomGroups WitnessScope = 0x20 +) diff --git a/pkg/core/util_test.go b/pkg/core/util_test.go index 5bf66555d..1c66de845 100644 --- a/pkg/core/util_test.go +++ b/pkg/core/util_test.go @@ -20,7 +20,7 @@ func TestGenesisBlockMainNet(t *testing.T) { // have been changed. Consequently, hash of the genesis block has been changed. // Update expected genesis block hash for better times. // Old hash is "d42561e3d30e15be6400b6df2f328e02d2bf6354c41dce433bc57687c82144bf" - expect := "16ffda4cc6a9b0a0ca63f1571f7724418c43f014e2eb4e8614b4938ccf0f20f6" + expect := "8eb36fe47f07a795a1783a9f066603db66c5b76cf878650b1e137c114f46c0cc" assert.Equal(t, expect, block.Hash().StringLE()) } @@ -47,7 +47,7 @@ func TestUtilityTokenTX(t *testing.T) { //TODO: After we added Nonce field to transaction.Transaction, UtilityTockenTx hash // has been changed. Update it for better times. // Old hash is "602c79718b16e442de58778e148d0b1084e3b2dffd5de6b7b16cee7969282de7" - expect := "b16384a950ed01ed5fc15c03fe7b98228871cb43b1bc22d67029449fc854d104" + expect := "8ef63ccd6f4ea20a93e7f4e84b2d43f778077612b241d617e42e1750cca4f2c5" assert.Equal(t, expect, UtilityTokenID().StringLE()) } @@ -55,6 +55,6 @@ func TestGoverningTokenTX(t *testing.T) { //TODO: After we added Nonce field to transaction.Transaction, GoveringTockenTx hash // has been changed. Update it for better times. // Old hash is "c56f33fc6ecfcd0c225c4ab356fee59390af8560be0e930faebe74a6daff7c9b" - expect := "7a37715546c6cfa5bac8d7f7e87c667a1e5a6ba0601238be475ab8c79a5abcf5" + expect := "7dc12f8835b085d468ddbab3f7152c0e2f5679b5815b2028685abb4608e7b7dc" assert.Equal(t, expect, GoverningTokenID().StringLE()) } diff --git a/pkg/rpc/client/nep5.go b/pkg/rpc/client/nep5.go index e16f6ed20..5535d34e8 100644 --- a/pkg/rpc/client/nep5.go +++ b/pkg/rpc/client/nep5.go @@ -108,22 +108,13 @@ func (c *Client) TransferNEP5(acc *wallet.Account, to util.Uint160, token *walle emit.Opcode(w.BinWriter, opcode.THROWIFNOT) tx := transaction.NewInvocationTX(w.Bytes(), gas) - tx.Attributes = append(tx.Attributes, transaction.Attribute{ - Usage: transaction.Script, - Data: from.BytesBE(), - }) + tx.Sender = from tx.ValidUntilBlock, err = c.CalculateValidUntilBlock() if err != nil { return util.Uint256{}, fmt.Errorf("can't calculate validUntilBlock: %v", err) } - addr, err := address.StringToUint160(acc.Address) - if err != nil { - return util.Uint256{}, fmt.Errorf("failed to get address: %v", err) - } - tx.Sender = addr - if err := request.AddInputsAndUnspentsToTx(tx, acc.Address, core.UtilityTokenID(), gas, c); err != nil { return util.Uint256{}, fmt.Errorf("can't add GAS to transaction: %v", err) } diff --git a/pkg/rpc/client/rpc_test.go b/pkg/rpc/client/rpc_test.go index d56168c28..6a4b1aba8 100644 --- a/pkg/rpc/client/rpc_test.go +++ b/pkg/rpc/client/rpc_test.go @@ -38,7 +38,7 @@ var rpcClientTestCases = map[string][]rpcClientTestCase{ invoke: func(c *Client) (interface{}, error) { return c.GetAccountState("") }, - serverResponse: `{"jsonrpc":"2.0","id": 1,"result":{"version":0,"script_hash":"0x1179716da2e9523d153a35fb3ad10c561b1e5b1a","frozen":false,"votes":[],"balances":[{"asset":"0x7a37715546c6cfa5bac8d7f7e87c667a1e5a6ba0601238be475ab8c79a5abcf5","value":"94"}]}}`, + serverResponse: `{"jsonrpc":"2.0","id": 1,"result":{"version":0,"script_hash":"0x1179716da2e9523d153a35fb3ad10c561b1e5b1a","frozen":false,"votes":[],"balances":[{"asset":"0x7dc12f8835b085d468ddbab3f7152c0e2f5679b5815b2028685abb4608e7b7dc","value":"94"}]}}`, result: func(c *Client) interface{} { scriptHash, err := util.Uint160DecodeStringLE("1179716da2e9523d153a35fb3ad10c561b1e5b1a") if err != nil { @@ -96,7 +96,7 @@ var rpcClientTestCases = map[string][]rpcClientTestCase{ invoke: func(c *Client) (interface{}, error) { return c.GetAssetState(util.Uint256{}) }, - serverResponse: `{"id":1,"jsonrpc":"2.0","result":{"id":"0x7a37715546c6cfa5bac8d7f7e87c667a1e5a6ba0601238be475ab8c79a5abcf5","type":0,"name":"NEO","amount":"100000000","available":"100000000","precision":0,"owner":"00","admin":"Abf2qMs1pzQb8kYk9RuxtUb9jtRKJVuBJt","issuer":"AFmseVrdL9f9oyCzZefL9tG6UbvhPbdYzM","expiration":4000000,"is_frozen":false}}`, + serverResponse: `{"id":1,"jsonrpc":"2.0","result":{"id":"0x7dc12f8835b085d468ddbab3f7152c0e2f5679b5815b2028685abb4608e7b7dc","type":0,"name":"NEO","amount":"100000000","available":"100000000","precision":0,"owner":"00","admin":"Abf2qMs1pzQb8kYk9RuxtUb9jtRKJVuBJt","issuer":"AFmseVrdL9f9oyCzZefL9tG6UbvhPbdYzM","expiration":4000000,"is_frozen":false}}`, result: func(c *Client) interface{} { return &result.AssetState{ ID: core.GoverningTokenID(), @@ -134,45 +134,45 @@ var rpcClientTestCases = map[string][]rpcClientTestCase{ { name: "byIndex_positive", invoke: func(c *Client) (interface{}, error) { - return c.GetBlockByIndex(5) + return c.GetBlockByIndex(202) }, - serverResponse: `{"id":1,"jsonrpc":"2.0","result":"000000005b25cf560918b13cc7a10071cf616426a103d58498171567aaa116af69179aa3c05c359ade4316392d69d5ca01f8860f8bdebbe1a8f752edd68d9a6a2d204fe752cca25e0000000005000000e903736ceceeceae1806eee0e3ec61e7cce476ce01fd08010c407f70912fdcd0ce9a70963110eb39ef73ed02512ea63bc1c55577474df8f364a874999b16666888f8a3ca69873054a31ab42dd1fee1ed8605ff65edb39797e34e0c40d59459cb1cc8270d9a813aa444852a5d7714aed0b25373ec07549349c6db32b6c8c2e43cdd7b1ad2a4154cb5ff1222d9d7010877016a59775abdd2c08f253c850c4048b65cb58e0d58f2dd0f5db3b195c5784933d6179d8317217ba46f9deac9a667bffb1afd0dd86bdae6267af4c2605f7401849a0b980fcecfeae95df7f5ca6e140c406d9b1942c5aa80070ad484b3dd76421a3f46327670bea94e3ecb3a94eef8843a75195b55872a7c503acb01ab368cdaa11a9e5fb80d55bbd6b861233ba84edcf894130c2102103a7f7dd016558597f7960d27c516a4394fd968b9e65155eb4b013e4040406e0c2102a7bc55fe8684e0119768d104ba30795bdcc86619e864add26156723ed185cd620c2102b3622bf4017bdfe317c58aed5f4c753f206b7db896046fa7d774bbc4bf7f8dc20c2103d90c07df63e690ce77912e10ab51acc944b66860237b608c4f8f8309e71ee699140b683073b3bb020057040000000000008000d5040000e903736ceceeceae1806eee0e3ec61e7cce476ce0500000000000001fd08010c40ae62dadb95b21628921adb9ee14e8c1f20d68b9d6ffba218f8e403af70126449435a53525cd6f1d1c871e64a91025866cd8a413ec70e3cde0ddf62931aa22baa0c40c3e09fc8ad46789d645240634ef40bd180e0dba75beae07a37dc2e899b68b4b3b3a67d076ea9444ed143dbb3264702914a4662ff95859d32c9b5bb5bdc9ec1d60c40b2511115482bd860d85f57103fb8cce2cb45ba8461d4e164685b426cb5df1525e6f09dd7aa23db0fec2241bde7c925e22f3cba3824ea461455515dc2a1455f5e0c40c0aee2528e7fd75a0434f4d67da58507e8d349ca29e01e7eafa9f283e8b8c05d06587db7234f111730c14c8a4bfb7a1ffd9493b9696c71e68966c6bf4a832ab794130c2102103a7f7dd016558597f7960d27c516a4394fd968b9e65155eb4b013e4040406e0c2102a7bc55fe8684e0119768d104ba30795bdcc86619e864add26156723ed185cd620c2102b3622bf4017bdfe317c58aed5f4c753f206b7db896046fa7d774bbc4bf7f8dc20c2103d90c07df63e690ce77912e10ab51acc944b66860237b608c4f8f8309e71ee699140b683073b3bb"}`, + serverResponse: `{"id":1,"jsonrpc":"2.0","result":"0000000039f06b13aa6ee24d37db9b7868533b7988a6fb1e59c3fa6677dab7fd1f51326405f4fa24f061ffa04ab3127994530ee04c5e578a7b8109133dd142b6a31192cd9debaa5e00000000ca000000e903736ceceeceae1806eee0e3ec61e7cce476ce01fd08010c404617b6788538326383015c44ffddd4a05a4e200b65a26fc84234ae8b1e28ef27b7f139dc498c58071193d530ba83081701290eba8f7108397499f5556c16e3780c402131f2bdcc494c73a379e86c46f9e9fe9899a05b23928926b1eaaf816928e160fe971b82263aa1e7efa5f7e46bf99de735fc4fc5aeb81edfdc6a9b2e9fcfa1000c408cbae1582bb9d82de9ff030b8c729737f2157844c0ca29edcdbfed1dd5e2473e0061f0dc29412477417e2c1f7c55443f11b9bd6e0d0856d1ec00240be1b9b9a70c4034d1055531cf0522ac7e5dcd817cf3cd86997ae38da806dc789b1f16eb0005f00b9bc29f7372bb43a8fed040c6763b162c8a0d8e2d0b2d7476e22e0b2b77601094130c2102103a7f7dd016558597f7960d27c516a4394fd968b9e65155eb4b013e4040406e0c2102a7bc55fe8684e0119768d104ba30795bdcc86619e864add26156723ed185cd620c2102b3622bf4017bdfe317c58aed5f4c753f206b7db896046fa7d774bbc4bf7f8dc20c2103d90c07df63e690ce77912e10ab51acc944b66860237b608c4f8f8309e71ee699140b683073b3bb0200570400000000000080000300000075a94799633ed955dd85a8af314a5b435ab51903b0040000000001f6c31d4dd9edf7aea24168885ae82dc574d25e35a9b9b3063f3ea44226a3081f000001dcb7e70846bb5a6828205b81b579562f0e2c15f7b3badd68d485b035882fc17d00184a27db86230075a94799633ed955dd85a8af314a5b435ab5190301420c40bfce1ead7d53339440bb29745eed4ad9840875de4f970950065291e7a14cbd249bfbf777d9a997c5e00bbc08e8ce9fdd2cd13c45c3585b4939599ff84c6149ff290c2102b3622bf4017bdfe317c58aed5f4c753f206b7db896046fa7d774bbc4bf7f8dc20b680a906ad4"}`, result: func(c *Client) interface{} { return &block.Block{} }, check: func(t *testing.T, c *Client, result interface{}) { res, ok := result.(*block.Block) require.True(t, ok) assert.Equal(t, uint32(0), res.Version) - assert.Equal(t, "81b74dcfc3a42ef331eec2486231aba300ec9a95b024b0151214c76305d409bb", res.Hash().StringLE()) - assert.Equal(t, "a39a1769af16a1aa6715179884d503a1266461cf7100a1c73cb1180956cf255b", res.PrevHash.StringLE()) - assert.Equal(t, "e74f202d6a9a8dd6ed52f7a8e1bbde8b0f86f801cad5692d391643de9a355cc0", res.MerkleRoot.StringLE()) + assert.Equal(t, "75ab743487ce969792a4cb3c235d9ea5ff97af42b2646183c981437a077fbc45", res.Hash().StringLE()) + assert.Equal(t, "6432511ffdb7da7766fac3591efba688793b5368789bdb374de26eaa136bf039", res.PrevHash.StringLE()) + assert.Equal(t, "cd9211a3b642d13d1309817b8a575e4ce00e53947912b34aa0ff61f024faf405", res.MerkleRoot.StringLE()) assert.Equal(t, 1, len(res.Transactions)) - assert.Equal(t, "69d95138263dc54c07826ef1d76f9eb32ff6bf7fc3fc3281194b46ec7683ceb3", res.Transactions[0].Hash().StringLE()) + assert.Equal(t, "115975f7d1e9c4577ec839c6ea4ae32727616284e2d7cdc5a49e4e421b32e505", res.Transactions[0].Hash().StringLE()) }, }, { name: "byIndex_verbose_positive", invoke: func(c *Client) (i interface{}, err error) { - return c.GetBlockByIndexVerbose(5) + return c.GetBlockByIndexVerbose(202) }, - serverResponse: `{"id":1,"jsonrpc":"2.0","result":{"hash":"0x81b74dcfc3a42ef331eec2486231aba300ec9a95b024b0151214c76305d409bb","size":977,"version":0,"nextblockhash":"0xd08e408909ae24de3470a3f231f966e15719910cb7b1a30f356b3e784c1ddf6a","previousblockhash":"0xa39a1769af16a1aa6715179884d503a1266461cf7100a1c73cb1180956cf255b","merkleroot":"0xe74f202d6a9a8dd6ed52f7a8e1bbde8b0f86f801cad5692d391643de9a355cc0","time":1587727442,"index":5,"consensus_data":{"primary":0,"nonce":"0000000000000457"},"nextconsensus":"Ad1wDxzcRiRSryvJobNV211Tv7UUiziPXy","confirmations":203,"script":{"invocation":"0c407f70912fdcd0ce9a70963110eb39ef73ed02512ea63bc1c55577474df8f364a874999b16666888f8a3ca69873054a31ab42dd1fee1ed8605ff65edb39797e34e0c40d59459cb1cc8270d9a813aa444852a5d7714aed0b25373ec07549349c6db32b6c8c2e43cdd7b1ad2a4154cb5ff1222d9d7010877016a59775abdd2c08f253c850c4048b65cb58e0d58f2dd0f5db3b195c5784933d6179d8317217ba46f9deac9a667bffb1afd0dd86bdae6267af4c2605f7401849a0b980fcecfeae95df7f5ca6e140c406d9b1942c5aa80070ad484b3dd76421a3f46327670bea94e3ecb3a94eef8843a75195b55872a7c503acb01ab368cdaa11a9e5fb80d55bbd6b861233ba84edcf8","verification":"130c2102103a7f7dd016558597f7960d27c516a4394fd968b9e65155eb4b013e4040406e0c2102a7bc55fe8684e0119768d104ba30795bdcc86619e864add26156723ed185cd620c2102b3622bf4017bdfe317c58aed5f4c753f206b7db896046fa7d774bbc4bf7f8dc20c2103d90c07df63e690ce77912e10ab51acc944b66860237b608c4f8f8309e71ee699140b683073b3bb"},"tx":[{"sys_fee":"0","net_fee":"0","txid":"0x69d95138263dc54c07826ef1d76f9eb32ff6bf7fc3fc3281194b46ec7683ceb3","size":450,"type":"ContractTransaction","version":0,"nonce":1237,"sender":"Ad1wDxzcRiRSryvJobNV211Tv7UUiziPXy","valid_until_block":5,"attributes":[],"vin":[],"vout":[],"scripts":[{"invocation":"0c40ae62dadb95b21628921adb9ee14e8c1f20d68b9d6ffba218f8e403af70126449435a53525cd6f1d1c871e64a91025866cd8a413ec70e3cde0ddf62931aa22baa0c40c3e09fc8ad46789d645240634ef40bd180e0dba75beae07a37dc2e899b68b4b3b3a67d076ea9444ed143dbb3264702914a4662ff95859d32c9b5bb5bdc9ec1d60c40b2511115482bd860d85f57103fb8cce2cb45ba8461d4e164685b426cb5df1525e6f09dd7aa23db0fec2241bde7c925e22f3cba3824ea461455515dc2a1455f5e0c40c0aee2528e7fd75a0434f4d67da58507e8d349ca29e01e7eafa9f283e8b8c05d06587db7234f111730c14c8a4bfb7a1ffd9493b9696c71e68966c6bf4a832ab7","verification":"130c2102103a7f7dd016558597f7960d27c516a4394fd968b9e65155eb4b013e4040406e0c2102a7bc55fe8684e0119768d104ba30795bdcc86619e864add26156723ed185cd620c2102b3622bf4017bdfe317c58aed5f4c753f206b7db896046fa7d774bbc4bf7f8dc20c2103d90c07df63e690ce77912e10ab51acc944b66860237b608c4f8f8309e71ee699140b683073b3bb"}]}]}}`, + serverResponse: `{"id":1,"jsonrpc":"2.0","result":{"hash":"0x75ab743487ce969792a4cb3c235d9ea5ff97af42b2646183c981437a077fbc45","size":765,"version":0,"nextblockhash":"0xec27fed4ff8ad6a87bdd29aecee43e9ecb4e336321dac875d0b14d2aab1c5798","previousblockhash":"0x6432511ffdb7da7766fac3591efba688793b5368789bdb374de26eaa136bf039","merkleroot":"0xcd9211a3b642d13d1309817b8a575e4ce00e53947912b34aa0ff61f024faf405","time":1588259741,"index":202,"consensus_data":{"primary":0,"nonce":"0000000000000457"},"nextconsensus":"Ad1wDxzcRiRSryvJobNV211Tv7UUiziPXy","confirmations":6,"script":{"invocation":"0c404617b6788538326383015c44ffddd4a05a4e200b65a26fc84234ae8b1e28ef27b7f139dc498c58071193d530ba83081701290eba8f7108397499f5556c16e3780c402131f2bdcc494c73a379e86c46f9e9fe9899a05b23928926b1eaaf816928e160fe971b82263aa1e7efa5f7e46bf99de735fc4fc5aeb81edfdc6a9b2e9fcfa1000c408cbae1582bb9d82de9ff030b8c729737f2157844c0ca29edcdbfed1dd5e2473e0061f0dc29412477417e2c1f7c55443f11b9bd6e0d0856d1ec00240be1b9b9a70c4034d1055531cf0522ac7e5dcd817cf3cd86997ae38da806dc789b1f16eb0005f00b9bc29f7372bb43a8fed040c6763b162c8a0d8e2d0b2d7476e22e0b2b776010","verification":"130c2102103a7f7dd016558597f7960d27c516a4394fd968b9e65155eb4b013e4040406e0c2102a7bc55fe8684e0119768d104ba30795bdcc86619e864add26156723ed185cd620c2102b3622bf4017bdfe317c58aed5f4c753f206b7db896046fa7d774bbc4bf7f8dc20c2103d90c07df63e690ce77912e10ab51acc944b66860237b608c4f8f8309e71ee699140b683073b3bb"},"tx":[{"sys_fee":"0","net_fee":"0","txid":"0x115975f7d1e9c4577ec839c6ea4ae32727616284e2d7cdc5a49e4e421b32e505","size":238,"type":"ContractTransaction","version":0,"nonce":3,"sender":"ASW1VhcukJRrukCXRipY4BE9d9zy4mAYsR","valid_until_block":1200,"attributes":[],"cosigners":[],"vin":[{"txid":"0x1f08a32642a43e3f06b3b9a9355ed274c52de85a886841a2aef7edd94d1dc3f6","vout":0}],"vout":[{"address":"ASW1VhcukJRrukCXRipY4BE9d9zy4mAYsR","asset":"0x7dc12f8835b085d468ddbab3f7152c0e2f5679b5815b2028685abb4608e7b7dc","n":0,"value":"99999000"}],"scripts":[{"invocation":"0c40bfce1ead7d53339440bb29745eed4ad9840875de4f970950065291e7a14cbd249bfbf777d9a997c5e00bbc08e8ce9fdd2cd13c45c3585b4939599ff84c6149ff","verification":"0c2102b3622bf4017bdfe317c58aed5f4c753f206b7db896046fa7d774bbc4bf7f8dc20b680a906ad4"}]}]}}`, result: func(c *Client) interface{} { - hash, err := util.Uint256DecodeStringLE("81b74dcfc3a42ef331eec2486231aba300ec9a95b024b0151214c76305d409bb") + hash, err := util.Uint256DecodeStringLE("75ab743487ce969792a4cb3c235d9ea5ff97af42b2646183c981437a077fbc45") if err != nil { panic(err) } - nextBlockHash, err := util.Uint256DecodeStringLE("d08e408909ae24de3470a3f231f966e15719910cb7b1a30f356b3e784c1ddf6a") + nextBlockHash, err := util.Uint256DecodeStringLE("ec27fed4ff8ad6a87bdd29aecee43e9ecb4e336321dac875d0b14d2aab1c5798") if err != nil { panic(err) } - prevBlockHash, err := util.Uint256DecodeStringLE("a39a1769af16a1aa6715179884d503a1266461cf7100a1c73cb1180956cf255b") + prevBlockHash, err := util.Uint256DecodeStringLE("6432511ffdb7da7766fac3591efba688793b5368789bdb374de26eaa136bf039") if err != nil { panic(err) } - merkleRoot, err := util.Uint256DecodeStringLE("e74f202d6a9a8dd6ed52f7a8e1bbde8b0f86f801cad5692d391643de9a355cc0") + merkleRoot, err := util.Uint256DecodeStringLE("cd9211a3b642d13d1309817b8a575e4ce00e53947912b34aa0ff61f024faf405") if err != nil { panic(err) } - invScript, err := hex.DecodeString("0c407f70912fdcd0ce9a70963110eb39ef73ed02512ea63bc1c55577474df8f364a874999b16666888f8a3ca69873054a31ab42dd1fee1ed8605ff65edb39797e34e0c40d59459cb1cc8270d9a813aa444852a5d7714aed0b25373ec07549349c6db32b6c8c2e43cdd7b1ad2a4154cb5ff1222d9d7010877016a59775abdd2c08f253c850c4048b65cb58e0d58f2dd0f5db3b195c5784933d6179d8317217ba46f9deac9a667bffb1afd0dd86bdae6267af4c2605f7401849a0b980fcecfeae95df7f5ca6e140c406d9b1942c5aa80070ad484b3dd76421a3f46327670bea94e3ecb3a94eef8843a75195b55872a7c503acb01ab368cdaa11a9e5fb80d55bbd6b861233ba84edcf8") + invScript, err := hex.DecodeString("0c404617b6788538326383015c44ffddd4a05a4e200b65a26fc84234ae8b1e28ef27b7f139dc498c58071193d530ba83081701290eba8f7108397499f5556c16e3780c402131f2bdcc494c73a379e86c46f9e9fe9899a05b23928926b1eaaf816928e160fe971b82263aa1e7efa5f7e46bf99de735fc4fc5aeb81edfdc6a9b2e9fcfa1000c408cbae1582bb9d82de9ff030b8c729737f2157844c0ca29edcdbfed1dd5e2473e0061f0dc29412477417e2c1f7c55443f11b9bd6e0d0856d1ec00240be1b9b9a70c4034d1055531cf0522ac7e5dcd817cf3cd86997ae38da806dc789b1f16eb0005f00b9bc29f7372bb43a8fed040c6763b162c8a0d8e2d0b2d7476e22e0b2b776010") if err != nil { panic(err) } @@ -180,21 +180,29 @@ var rpcClientTestCases = map[string][]rpcClientTestCase{ if err != nil { panic(err) } - sender, err := address.StringToUint160("Ad1wDxzcRiRSryvJobNV211Tv7UUiziPXy") + sender, err := address.StringToUint160("ASW1VhcukJRrukCXRipY4BE9d9zy4mAYsR") if err != nil { panic(err) } - txInvScript, err := hex.DecodeString("0c40ae62dadb95b21628921adb9ee14e8c1f20d68b9d6ffba218f8e403af70126449435a53525cd6f1d1c871e64a91025866cd8a413ec70e3cde0ddf62931aa22baa0c40c3e09fc8ad46789d645240634ef40bd180e0dba75beae07a37dc2e899b68b4b3b3a67d076ea9444ed143dbb3264702914a4662ff95859d32c9b5bb5bdc9ec1d60c40b2511115482bd860d85f57103fb8cce2cb45ba8461d4e164685b426cb5df1525e6f09dd7aa23db0fec2241bde7c925e22f3cba3824ea461455515dc2a1455f5e0c40c0aee2528e7fd75a0434f4d67da58507e8d349ca29e01e7eafa9f283e8b8c05d06587db7234f111730c14c8a4bfb7a1ffd9493b9696c71e68966c6bf4a832ab7") + txInvScript, err := hex.DecodeString("0c40bfce1ead7d53339440bb29745eed4ad9840875de4f970950065291e7a14cbd249bfbf777d9a997c5e00bbc08e8ce9fdd2cd13c45c3585b4939599ff84c6149ff") if err != nil { panic(err) } - txVerifScript, err := hex.DecodeString("130c2102103a7f7dd016558597f7960d27c516a4394fd968b9e65155eb4b013e4040406e0c2102a7bc55fe8684e0119768d104ba30795bdcc86619e864add26156723ed185cd620c2102b3622bf4017bdfe317c58aed5f4c753f206b7db896046fa7d774bbc4bf7f8dc20c2103d90c07df63e690ce77912e10ab51acc944b66860237b608c4f8f8309e71ee699140b683073b3bb") + txVerifScript, err := hex.DecodeString("0c2102b3622bf4017bdfe317c58aed5f4c753f206b7db896046fa7d774bbc4bf7f8dc20b680a906ad4") + if err != nil { + panic(err) + } + vin, err := util.Uint256DecodeStringLE("1f08a32642a43e3f06b3b9a9355ed274c52de85a886841a2aef7edd94d1dc3f6") + if err != nil { + panic(err) + } + outAddress, err := address.StringToUint160("ASW1VhcukJRrukCXRipY4BE9d9zy4mAYsR") if err != nil { panic(err) } tx := transaction.NewContractTX() - tx.Nonce = 1237 - tx.ValidUntilBlock = 5 + tx.Nonce = 3 + tx.ValidUntilBlock = 1200 tx.Sender = sender tx.Scripts = []transaction.Witness{ { @@ -202,19 +210,34 @@ var rpcClientTestCases = map[string][]rpcClientTestCase{ VerificationScript: txVerifScript, }, } + tx.Inputs = []transaction.Input{ + { + PrevHash: vin, + PrevIndex: 0, + }, + } + tx.Outputs = []transaction.Output{ + { + AssetID: core.GoverningTokenID(), + Amount: util.Fixed8FromInt64(99999000), + ScriptHash: outAddress, + Position: 0, + }, + } + // Update hashes for correct result comparison. _ = tx.Hash() return &result.Block{ Hash: hash, - Size: 977, + Size: 765, Version: 0, NextBlockHash: &nextBlockHash, PreviousBlockHash: prevBlockHash, MerkleRoot: merkleRoot, - Time: 1587727442, - Index: 5, + Time: 1588259741, + Index: 202, NextConsensus: "Ad1wDxzcRiRSryvJobNV211Tv7UUiziPXy", - Confirmations: 203, + Confirmations: 6, ConsensusData: result.ConsensusData{ PrimaryIndex: 0, Nonce: "0000000000000457", @@ -236,53 +259,53 @@ var rpcClientTestCases = map[string][]rpcClientTestCase{ { name: "byHash_positive", invoke: func(c *Client) (interface{}, error) { - hash, err := util.Uint256DecodeStringLE("e9f71b58764157f1e2c3e29f217e654b57956ee7c8a60496b03ea85e39084b42") + hash, err := util.Uint256DecodeStringLE("45bc7f077a4381c9836164b242af97ffa59e5d233ccba4929796ce873474ab75") if err != nil { panic(err) } return c.GetBlockByHash(hash) }, - serverResponse: `{"id":1,"jsonrpc":"2.0","result":"000000005b25cf560918b13cc7a10071cf616426a103d58498171567aaa116af69179aa3c05c359ade4316392d69d5ca01f8860f8bdebbe1a8f752edd68d9a6a2d204fe752cca25e0000000005000000e903736ceceeceae1806eee0e3ec61e7cce476ce01fd08010c407f70912fdcd0ce9a70963110eb39ef73ed02512ea63bc1c55577474df8f364a874999b16666888f8a3ca69873054a31ab42dd1fee1ed8605ff65edb39797e34e0c40d59459cb1cc8270d9a813aa444852a5d7714aed0b25373ec07549349c6db32b6c8c2e43cdd7b1ad2a4154cb5ff1222d9d7010877016a59775abdd2c08f253c850c4048b65cb58e0d58f2dd0f5db3b195c5784933d6179d8317217ba46f9deac9a667bffb1afd0dd86bdae6267af4c2605f7401849a0b980fcecfeae95df7f5ca6e140c406d9b1942c5aa80070ad484b3dd76421a3f46327670bea94e3ecb3a94eef8843a75195b55872a7c503acb01ab368cdaa11a9e5fb80d55bbd6b861233ba84edcf894130c2102103a7f7dd016558597f7960d27c516a4394fd968b9e65155eb4b013e4040406e0c2102a7bc55fe8684e0119768d104ba30795bdcc86619e864add26156723ed185cd620c2102b3622bf4017bdfe317c58aed5f4c753f206b7db896046fa7d774bbc4bf7f8dc20c2103d90c07df63e690ce77912e10ab51acc944b66860237b608c4f8f8309e71ee699140b683073b3bb020057040000000000008000d5040000e903736ceceeceae1806eee0e3ec61e7cce476ce0500000000000001fd08010c40ae62dadb95b21628921adb9ee14e8c1f20d68b9d6ffba218f8e403af70126449435a53525cd6f1d1c871e64a91025866cd8a413ec70e3cde0ddf62931aa22baa0c40c3e09fc8ad46789d645240634ef40bd180e0dba75beae07a37dc2e899b68b4b3b3a67d076ea9444ed143dbb3264702914a4662ff95859d32c9b5bb5bdc9ec1d60c40b2511115482bd860d85f57103fb8cce2cb45ba8461d4e164685b426cb5df1525e6f09dd7aa23db0fec2241bde7c925e22f3cba3824ea461455515dc2a1455f5e0c40c0aee2528e7fd75a0434f4d67da58507e8d349ca29e01e7eafa9f283e8b8c05d06587db7234f111730c14c8a4bfb7a1ffd9493b9696c71e68966c6bf4a832ab794130c2102103a7f7dd016558597f7960d27c516a4394fd968b9e65155eb4b013e4040406e0c2102a7bc55fe8684e0119768d104ba30795bdcc86619e864add26156723ed185cd620c2102b3622bf4017bdfe317c58aed5f4c753f206b7db896046fa7d774bbc4bf7f8dc20c2103d90c07df63e690ce77912e10ab51acc944b66860237b608c4f8f8309e71ee699140b683073b3bb"}`, + serverResponse: `{"id":1,"jsonrpc":"2.0","result":"0000000039f06b13aa6ee24d37db9b7868533b7988a6fb1e59c3fa6677dab7fd1f51326405f4fa24f061ffa04ab3127994530ee04c5e578a7b8109133dd142b6a31192cd9debaa5e00000000ca000000e903736ceceeceae1806eee0e3ec61e7cce476ce01fd08010c404617b6788538326383015c44ffddd4a05a4e200b65a26fc84234ae8b1e28ef27b7f139dc498c58071193d530ba83081701290eba8f7108397499f5556c16e3780c402131f2bdcc494c73a379e86c46f9e9fe9899a05b23928926b1eaaf816928e160fe971b82263aa1e7efa5f7e46bf99de735fc4fc5aeb81edfdc6a9b2e9fcfa1000c408cbae1582bb9d82de9ff030b8c729737f2157844c0ca29edcdbfed1dd5e2473e0061f0dc29412477417e2c1f7c55443f11b9bd6e0d0856d1ec00240be1b9b9a70c4034d1055531cf0522ac7e5dcd817cf3cd86997ae38da806dc789b1f16eb0005f00b9bc29f7372bb43a8fed040c6763b162c8a0d8e2d0b2d7476e22e0b2b77601094130c2102103a7f7dd016558597f7960d27c516a4394fd968b9e65155eb4b013e4040406e0c2102a7bc55fe8684e0119768d104ba30795bdcc86619e864add26156723ed185cd620c2102b3622bf4017bdfe317c58aed5f4c753f206b7db896046fa7d774bbc4bf7f8dc20c2103d90c07df63e690ce77912e10ab51acc944b66860237b608c4f8f8309e71ee699140b683073b3bb0200570400000000000080000300000075a94799633ed955dd85a8af314a5b435ab51903b0040000000001f6c31d4dd9edf7aea24168885ae82dc574d25e35a9b9b3063f3ea44226a3081f000001dcb7e70846bb5a6828205b81b579562f0e2c15f7b3badd68d485b035882fc17d00184a27db86230075a94799633ed955dd85a8af314a5b435ab5190301420c40bfce1ead7d53339440bb29745eed4ad9840875de4f970950065291e7a14cbd249bfbf777d9a997c5e00bbc08e8ce9fdd2cd13c45c3585b4939599ff84c6149ff290c2102b3622bf4017bdfe317c58aed5f4c753f206b7db896046fa7d774bbc4bf7f8dc20b680a906ad4"}`, result: func(c *Client) interface{} { return &block.Block{} }, check: func(t *testing.T, c *Client, result interface{}) { res, ok := result.(*block.Block) require.True(t, ok) assert.Equal(t, uint32(0), res.Version) - assert.Equal(t, "81b74dcfc3a42ef331eec2486231aba300ec9a95b024b0151214c76305d409bb", res.Hash().StringLE()) - assert.Equal(t, "a39a1769af16a1aa6715179884d503a1266461cf7100a1c73cb1180956cf255b", res.PrevHash.StringLE()) - assert.Equal(t, "e74f202d6a9a8dd6ed52f7a8e1bbde8b0f86f801cad5692d391643de9a355cc0", res.MerkleRoot.StringLE()) + assert.Equal(t, "75ab743487ce969792a4cb3c235d9ea5ff97af42b2646183c981437a077fbc45", res.Hash().StringLE()) + assert.Equal(t, "6432511ffdb7da7766fac3591efba688793b5368789bdb374de26eaa136bf039", res.PrevHash.StringLE()) + assert.Equal(t, "cd9211a3b642d13d1309817b8a575e4ce00e53947912b34aa0ff61f024faf405", res.MerkleRoot.StringLE()) assert.Equal(t, 1, len(res.Transactions)) - assert.Equal(t, "69d95138263dc54c07826ef1d76f9eb32ff6bf7fc3fc3281194b46ec7683ceb3", res.Transactions[0].Hash().StringLE()) + assert.Equal(t, "115975f7d1e9c4577ec839c6ea4ae32727616284e2d7cdc5a49e4e421b32e505", res.Transactions[0].Hash().StringLE()) }, }, { name: "byHash_verbose_positive", invoke: func(c *Client) (i interface{}, err error) { - hash, err := util.Uint256DecodeStringLE("bb09d40563c7141215b024b0959aec00a3ab316248c2ee31f32ea4c3cf4db781") + hash, err := util.Uint256DecodeStringLE("45bc7f077a4381c9836164b242af97ffa59e5d233ccba4929796ce873474ab75") if err != nil { panic(err) } return c.GetBlockByHashVerbose(hash) }, - serverResponse: `{"id":1,"jsonrpc":"2.0","result":{"hash":"0x81b74dcfc3a42ef331eec2486231aba300ec9a95b024b0151214c76305d409bb","size":977,"version":0,"nextblockhash":"0xd08e408909ae24de3470a3f231f966e15719910cb7b1a30f356b3e784c1ddf6a","previousblockhash":"0xa39a1769af16a1aa6715179884d503a1266461cf7100a1c73cb1180956cf255b","merkleroot":"0xe74f202d6a9a8dd6ed52f7a8e1bbde8b0f86f801cad5692d391643de9a355cc0","time":1587727442,"index":5,"consensus_data":{"primary":0,"nonce":"0000000000000457"},"nextconsensus":"Ad1wDxzcRiRSryvJobNV211Tv7UUiziPXy","confirmations":203,"script":{"invocation":"0c407f70912fdcd0ce9a70963110eb39ef73ed02512ea63bc1c55577474df8f364a874999b16666888f8a3ca69873054a31ab42dd1fee1ed8605ff65edb39797e34e0c40d59459cb1cc8270d9a813aa444852a5d7714aed0b25373ec07549349c6db32b6c8c2e43cdd7b1ad2a4154cb5ff1222d9d7010877016a59775abdd2c08f253c850c4048b65cb58e0d58f2dd0f5db3b195c5784933d6179d8317217ba46f9deac9a667bffb1afd0dd86bdae6267af4c2605f7401849a0b980fcecfeae95df7f5ca6e140c406d9b1942c5aa80070ad484b3dd76421a3f46327670bea94e3ecb3a94eef8843a75195b55872a7c503acb01ab368cdaa11a9e5fb80d55bbd6b861233ba84edcf8","verification":"130c2102103a7f7dd016558597f7960d27c516a4394fd968b9e65155eb4b013e4040406e0c2102a7bc55fe8684e0119768d104ba30795bdcc86619e864add26156723ed185cd620c2102b3622bf4017bdfe317c58aed5f4c753f206b7db896046fa7d774bbc4bf7f8dc20c2103d90c07df63e690ce77912e10ab51acc944b66860237b608c4f8f8309e71ee699140b683073b3bb"},"tx":[{"sys_fee":"0","net_fee":"0","txid":"0x69d95138263dc54c07826ef1d76f9eb32ff6bf7fc3fc3281194b46ec7683ceb3","size":450,"type":"ContractTransaction","version":0,"nonce":1237,"sender":"Ad1wDxzcRiRSryvJobNV211Tv7UUiziPXy","valid_until_block":5,"attributes":[],"vin":[],"vout":[],"scripts":[{"invocation":"0c40ae62dadb95b21628921adb9ee14e8c1f20d68b9d6ffba218f8e403af70126449435a53525cd6f1d1c871e64a91025866cd8a413ec70e3cde0ddf62931aa22baa0c40c3e09fc8ad46789d645240634ef40bd180e0dba75beae07a37dc2e899b68b4b3b3a67d076ea9444ed143dbb3264702914a4662ff95859d32c9b5bb5bdc9ec1d60c40b2511115482bd860d85f57103fb8cce2cb45ba8461d4e164685b426cb5df1525e6f09dd7aa23db0fec2241bde7c925e22f3cba3824ea461455515dc2a1455f5e0c40c0aee2528e7fd75a0434f4d67da58507e8d349ca29e01e7eafa9f283e8b8c05d06587db7234f111730c14c8a4bfb7a1ffd9493b9696c71e68966c6bf4a832ab7","verification":"130c2102103a7f7dd016558597f7960d27c516a4394fd968b9e65155eb4b013e4040406e0c2102a7bc55fe8684e0119768d104ba30795bdcc86619e864add26156723ed185cd620c2102b3622bf4017bdfe317c58aed5f4c753f206b7db896046fa7d774bbc4bf7f8dc20c2103d90c07df63e690ce77912e10ab51acc944b66860237b608c4f8f8309e71ee699140b683073b3bb"}]}]}}`, + serverResponse: `{"id":1,"jsonrpc":"2.0","result":{"hash":"0x75ab743487ce969792a4cb3c235d9ea5ff97af42b2646183c981437a077fbc45","size":765,"version":0,"nextblockhash":"0xec27fed4ff8ad6a87bdd29aecee43e9ecb4e336321dac875d0b14d2aab1c5798","previousblockhash":"0x6432511ffdb7da7766fac3591efba688793b5368789bdb374de26eaa136bf039","merkleroot":"0xcd9211a3b642d13d1309817b8a575e4ce00e53947912b34aa0ff61f024faf405","time":1588259741,"index":202,"consensus_data":{"primary":0,"nonce":"0000000000000457"},"nextconsensus":"Ad1wDxzcRiRSryvJobNV211Tv7UUiziPXy","confirmations":6,"script":{"invocation":"0c404617b6788538326383015c44ffddd4a05a4e200b65a26fc84234ae8b1e28ef27b7f139dc498c58071193d530ba83081701290eba8f7108397499f5556c16e3780c402131f2bdcc494c73a379e86c46f9e9fe9899a05b23928926b1eaaf816928e160fe971b82263aa1e7efa5f7e46bf99de735fc4fc5aeb81edfdc6a9b2e9fcfa1000c408cbae1582bb9d82de9ff030b8c729737f2157844c0ca29edcdbfed1dd5e2473e0061f0dc29412477417e2c1f7c55443f11b9bd6e0d0856d1ec00240be1b9b9a70c4034d1055531cf0522ac7e5dcd817cf3cd86997ae38da806dc789b1f16eb0005f00b9bc29f7372bb43a8fed040c6763b162c8a0d8e2d0b2d7476e22e0b2b776010","verification":"130c2102103a7f7dd016558597f7960d27c516a4394fd968b9e65155eb4b013e4040406e0c2102a7bc55fe8684e0119768d104ba30795bdcc86619e864add26156723ed185cd620c2102b3622bf4017bdfe317c58aed5f4c753f206b7db896046fa7d774bbc4bf7f8dc20c2103d90c07df63e690ce77912e10ab51acc944b66860237b608c4f8f8309e71ee699140b683073b3bb"},"tx":[{"sys_fee":"0","net_fee":"0","txid":"0x115975f7d1e9c4577ec839c6ea4ae32727616284e2d7cdc5a49e4e421b32e505","size":238,"type":"ContractTransaction","version":0,"nonce":3,"sender":"ASW1VhcukJRrukCXRipY4BE9d9zy4mAYsR","valid_until_block":1200,"attributes":[],"cosigners":[],"vin":[{"txid":"0x1f08a32642a43e3f06b3b9a9355ed274c52de85a886841a2aef7edd94d1dc3f6","vout":0}],"vout":[{"address":"ASW1VhcukJRrukCXRipY4BE9d9zy4mAYsR","asset":"0x7dc12f8835b085d468ddbab3f7152c0e2f5679b5815b2028685abb4608e7b7dc","n":0,"value":"99999000"}],"scripts":[{"invocation":"0c40bfce1ead7d53339440bb29745eed4ad9840875de4f970950065291e7a14cbd249bfbf777d9a997c5e00bbc08e8ce9fdd2cd13c45c3585b4939599ff84c6149ff","verification":"0c2102b3622bf4017bdfe317c58aed5f4c753f206b7db896046fa7d774bbc4bf7f8dc20b680a906ad4"}]}]}}`, result: func(c *Client) interface{} { - hash, err := util.Uint256DecodeStringLE("81b74dcfc3a42ef331eec2486231aba300ec9a95b024b0151214c76305d409bb") + hash, err := util.Uint256DecodeStringLE("75ab743487ce969792a4cb3c235d9ea5ff97af42b2646183c981437a077fbc45") if err != nil { panic(err) } - nextBlockHash, err := util.Uint256DecodeStringLE("d08e408909ae24de3470a3f231f966e15719910cb7b1a30f356b3e784c1ddf6a") + nextBlockHash, err := util.Uint256DecodeStringLE("ec27fed4ff8ad6a87bdd29aecee43e9ecb4e336321dac875d0b14d2aab1c5798") if err != nil { panic(err) } - prevBlockHash, err := util.Uint256DecodeStringLE("a39a1769af16a1aa6715179884d503a1266461cf7100a1c73cb1180956cf255b") + prevBlockHash, err := util.Uint256DecodeStringLE("6432511ffdb7da7766fac3591efba688793b5368789bdb374de26eaa136bf039") if err != nil { panic(err) } - merkleRoot, err := util.Uint256DecodeStringLE("e74f202d6a9a8dd6ed52f7a8e1bbde8b0f86f801cad5692d391643de9a355cc0") + merkleRoot, err := util.Uint256DecodeStringLE("cd9211a3b642d13d1309817b8a575e4ce00e53947912b34aa0ff61f024faf405") if err != nil { panic(err) } - invScript, err := hex.DecodeString("0c407f70912fdcd0ce9a70963110eb39ef73ed02512ea63bc1c55577474df8f364a874999b16666888f8a3ca69873054a31ab42dd1fee1ed8605ff65edb39797e34e0c40d59459cb1cc8270d9a813aa444852a5d7714aed0b25373ec07549349c6db32b6c8c2e43cdd7b1ad2a4154cb5ff1222d9d7010877016a59775abdd2c08f253c850c4048b65cb58e0d58f2dd0f5db3b195c5784933d6179d8317217ba46f9deac9a667bffb1afd0dd86bdae6267af4c2605f7401849a0b980fcecfeae95df7f5ca6e140c406d9b1942c5aa80070ad484b3dd76421a3f46327670bea94e3ecb3a94eef8843a75195b55872a7c503acb01ab368cdaa11a9e5fb80d55bbd6b861233ba84edcf8") + invScript, err := hex.DecodeString("0c404617b6788538326383015c44ffddd4a05a4e200b65a26fc84234ae8b1e28ef27b7f139dc498c58071193d530ba83081701290eba8f7108397499f5556c16e3780c402131f2bdcc494c73a379e86c46f9e9fe9899a05b23928926b1eaaf816928e160fe971b82263aa1e7efa5f7e46bf99de735fc4fc5aeb81edfdc6a9b2e9fcfa1000c408cbae1582bb9d82de9ff030b8c729737f2157844c0ca29edcdbfed1dd5e2473e0061f0dc29412477417e2c1f7c55443f11b9bd6e0d0856d1ec00240be1b9b9a70c4034d1055531cf0522ac7e5dcd817cf3cd86997ae38da806dc789b1f16eb0005f00b9bc29f7372bb43a8fed040c6763b162c8a0d8e2d0b2d7476e22e0b2b776010") if err != nil { panic(err) } @@ -290,21 +313,29 @@ var rpcClientTestCases = map[string][]rpcClientTestCase{ if err != nil { panic(err) } - sender, err := address.StringToUint160("Ad1wDxzcRiRSryvJobNV211Tv7UUiziPXy") + sender, err := address.StringToUint160("ASW1VhcukJRrukCXRipY4BE9d9zy4mAYsR") if err != nil { panic(err) } - txInvScript, err := hex.DecodeString("0c40ae62dadb95b21628921adb9ee14e8c1f20d68b9d6ffba218f8e403af70126449435a53525cd6f1d1c871e64a91025866cd8a413ec70e3cde0ddf62931aa22baa0c40c3e09fc8ad46789d645240634ef40bd180e0dba75beae07a37dc2e899b68b4b3b3a67d076ea9444ed143dbb3264702914a4662ff95859d32c9b5bb5bdc9ec1d60c40b2511115482bd860d85f57103fb8cce2cb45ba8461d4e164685b426cb5df1525e6f09dd7aa23db0fec2241bde7c925e22f3cba3824ea461455515dc2a1455f5e0c40c0aee2528e7fd75a0434f4d67da58507e8d349ca29e01e7eafa9f283e8b8c05d06587db7234f111730c14c8a4bfb7a1ffd9493b9696c71e68966c6bf4a832ab7") + txInvScript, err := hex.DecodeString("0c40bfce1ead7d53339440bb29745eed4ad9840875de4f970950065291e7a14cbd249bfbf777d9a997c5e00bbc08e8ce9fdd2cd13c45c3585b4939599ff84c6149ff") if err != nil { panic(err) } - txVerifScript, err := hex.DecodeString("130c2102103a7f7dd016558597f7960d27c516a4394fd968b9e65155eb4b013e4040406e0c2102a7bc55fe8684e0119768d104ba30795bdcc86619e864add26156723ed185cd620c2102b3622bf4017bdfe317c58aed5f4c753f206b7db896046fa7d774bbc4bf7f8dc20c2103d90c07df63e690ce77912e10ab51acc944b66860237b608c4f8f8309e71ee699140b683073b3bb") + txVerifScript, err := hex.DecodeString("0c2102b3622bf4017bdfe317c58aed5f4c753f206b7db896046fa7d774bbc4bf7f8dc20b680a906ad4") + if err != nil { + panic(err) + } + vin, err := util.Uint256DecodeStringLE("1f08a32642a43e3f06b3b9a9355ed274c52de85a886841a2aef7edd94d1dc3f6") + if err != nil { + panic(err) + } + outAddress, err := address.StringToUint160("ASW1VhcukJRrukCXRipY4BE9d9zy4mAYsR") if err != nil { panic(err) } tx := transaction.NewContractTX() - tx.Nonce = 1237 - tx.ValidUntilBlock = 5 + tx.Nonce = 3 + tx.ValidUntilBlock = 1200 tx.Sender = sender tx.Scripts = []transaction.Witness{ { @@ -312,19 +343,34 @@ var rpcClientTestCases = map[string][]rpcClientTestCase{ VerificationScript: txVerifScript, }, } + tx.Inputs = []transaction.Input{ + { + PrevHash: vin, + PrevIndex: 0, + }, + } + tx.Outputs = []transaction.Output{ + { + AssetID: core.GoverningTokenID(), + Amount: util.Fixed8FromInt64(99999000), + ScriptHash: outAddress, + Position: 0, + }, + } + // Update hashes for correct result comparison. _ = tx.Hash() return &result.Block{ Hash: hash, - Size: 977, + Size: 765, Version: 0, NextBlockHash: &nextBlockHash, PreviousBlockHash: prevBlockHash, MerkleRoot: merkleRoot, - Time: 1587727442, - Index: 5, + Time: 1588259741, + Index: 202, NextConsensus: "Ad1wDxzcRiRSryvJobNV211Tv7UUiziPXy", - Confirmations: 203, + Confirmations: 6, ConsensusData: result.ConsensusData{ PrimaryIndex: 0, Nonce: "0000000000000457", @@ -653,19 +699,19 @@ var rpcClientTestCases = map[string][]rpcClientTestCase{ { name: "positive", invoke: func(c *Client) (i interface{}, err error) { - hash, err := util.Uint256DecodeStringLE("b3ce8376ec464b198132fcc37fbff62fb39e6fd7f16e82074cc53d263851d969") + hash, err := util.Uint256DecodeStringLE("05e5321b424e9ea4c5cdd7e28462612727e34aeac639c87e57c4e9d1f7755911") if err != nil { panic(err) } return c.GetRawTransaction(hash) }, - serverResponse: `{"id":1,"jsonrpc":"2.0","result":"8000d5040000e903736ceceeceae1806eee0e3ec61e7cce476ce0500000000000001fd08010c40ae62dadb95b21628921adb9ee14e8c1f20d68b9d6ffba218f8e403af70126449435a53525cd6f1d1c871e64a91025866cd8a413ec70e3cde0ddf62931aa22baa0c40c3e09fc8ad46789d645240634ef40bd180e0dba75beae07a37dc2e899b68b4b3b3a67d076ea9444ed143dbb3264702914a4662ff95859d32c9b5bb5bdc9ec1d60c40b2511115482bd860d85f57103fb8cce2cb45ba8461d4e164685b426cb5df1525e6f09dd7aa23db0fec2241bde7c925e22f3cba3824ea461455515dc2a1455f5e0c40c0aee2528e7fd75a0434f4d67da58507e8d349ca29e01e7eafa9f283e8b8c05d06587db7234f111730c14c8a4bfb7a1ffd9493b9696c71e68966c6bf4a832ab794130c2102103a7f7dd016558597f7960d27c516a4394fd968b9e65155eb4b013e4040406e0c2102a7bc55fe8684e0119768d104ba30795bdcc86619e864add26156723ed185cd620c2102b3622bf4017bdfe317c58aed5f4c753f206b7db896046fa7d774bbc4bf7f8dc20c2103d90c07df63e690ce77912e10ab51acc944b66860237b608c4f8f8309e71ee699140b683073b3bb"}`, + serverResponse: `{"id":1,"jsonrpc":"2.0","result":"80000300000075a94799633ed955dd85a8af314a5b435ab51903b0040000000001f6c31d4dd9edf7aea24168885ae82dc574d25e35a9b9b3063f3ea44226a3081f000001dcb7e70846bb5a6828205b81b579562f0e2c15f7b3badd68d485b035882fc17d00184a27db86230075a94799633ed955dd85a8af314a5b435ab5190301420c40bfce1ead7d53339440bb29745eed4ad9840875de4f970950065291e7a14cbd249bfbf777d9a997c5e00bbc08e8ce9fdd2cd13c45c3585b4939599ff84c6149ff290c2102b3622bf4017bdfe317c58aed5f4c753f206b7db896046fa7d774bbc4bf7f8dc20b680a906ad4"}`, result: func(c *Client) interface{} { return &transaction.Transaction{} }, check: func(t *testing.T, c *Client, result interface{}) { res, ok := result.(*transaction.Transaction) require.True(t, ok) assert.Equal(t, uint8(0), res.Version) - assert.Equal(t, "b3ce8376ec464b198132fcc37fbff62fb39e6fd7f16e82074cc53d263851d969", res.Hash().StringBE()) + assert.Equal(t, "05e5321b424e9ea4c5cdd7e28462612727e34aeac639c87e57c4e9d1f7755911", res.Hash().StringBE()) assert.Equal(t, transaction.ContractType, res.Type) assert.Equal(t, false, res.Trimmed) }, @@ -673,33 +719,41 @@ var rpcClientTestCases = map[string][]rpcClientTestCase{ { name: "verbose_positive", invoke: func(c *Client) (interface{}, error) { - hash, err := util.Uint256DecodeStringLE("b3ce8376ec464b198132fcc37fbff62fb39e6fd7f16e82074cc53d263851d969") + hash, err := util.Uint256DecodeStringLE("05e5321b424e9ea4c5cdd7e28462612727e34aeac639c87e57c4e9d1f7755911") if err != nil { panic(err) } return c.GetRawTransactionVerbose(hash) }, - serverResponse: `{"jsonrpc":"2.0","id":1,"result":{"sys_fee":"0","net_fee":"0","blockhash":"0x81b74dcfc3a42ef331eec2486231aba300ec9a95b024b0151214c76305d409bb","confirmations":205,"blocktime":1587727442,"txid":"0x69d95138263dc54c07826ef1d76f9eb32ff6bf7fc3fc3281194b46ec7683ceb3","size":450,"type":"ContractTransaction","version":0,"nonce":1237,"sender":"Ad1wDxzcRiRSryvJobNV211Tv7UUiziPXy","valid_until_block":5,"attributes":[],"vin":[],"vout":[],"scripts":[{"invocation":"0c40ae62dadb95b21628921adb9ee14e8c1f20d68b9d6ffba218f8e403af70126449435a53525cd6f1d1c871e64a91025866cd8a413ec70e3cde0ddf62931aa22baa0c40c3e09fc8ad46789d645240634ef40bd180e0dba75beae07a37dc2e899b68b4b3b3a67d076ea9444ed143dbb3264702914a4662ff95859d32c9b5bb5bdc9ec1d60c40b2511115482bd860d85f57103fb8cce2cb45ba8461d4e164685b426cb5df1525e6f09dd7aa23db0fec2241bde7c925e22f3cba3824ea461455515dc2a1455f5e0c40c0aee2528e7fd75a0434f4d67da58507e8d349ca29e01e7eafa9f283e8b8c05d06587db7234f111730c14c8a4bfb7a1ffd9493b9696c71e68966c6bf4a832ab7","verification":"130c2102103a7f7dd016558597f7960d27c516a4394fd968b9e65155eb4b013e4040406e0c2102a7bc55fe8684e0119768d104ba30795bdcc86619e864add26156723ed185cd620c2102b3622bf4017bdfe317c58aed5f4c753f206b7db896046fa7d774bbc4bf7f8dc20c2103d90c07df63e690ce77912e10ab51acc944b66860237b608c4f8f8309e71ee699140b683073b3bb"}]}}`, + serverResponse: `{"jsonrpc":"2.0","id":1,"result":{"sys_fee":"0","net_fee":"0","blockhash":"0x75ab743487ce969792a4cb3c235d9ea5ff97af42b2646183c981437a077fbc45","confirmations":8,"blocktime":1588259741,"txid":"0x115975f7d1e9c4577ec839c6ea4ae32727616284e2d7cdc5a49e4e421b32e505","size":238,"type":"ContractTransaction","version":0,"nonce":3,"sender":"ASW1VhcukJRrukCXRipY4BE9d9zy4mAYsR","valid_until_block":1200,"attributes":[],"cosigners":[],"vin":[{"txid":"0x1f08a32642a43e3f06b3b9a9355ed274c52de85a886841a2aef7edd94d1dc3f6","vout":0}],"vout":[{"address":"ASW1VhcukJRrukCXRipY4BE9d9zy4mAYsR","asset":"0x7dc12f8835b085d468ddbab3f7152c0e2f5679b5815b2028685abb4608e7b7dc","n":0,"value":"99999000"}],"scripts":[{"invocation":"0c40bfce1ead7d53339440bb29745eed4ad9840875de4f970950065291e7a14cbd249bfbf777d9a997c5e00bbc08e8ce9fdd2cd13c45c3585b4939599ff84c6149ff","verification":"0c2102b3622bf4017bdfe317c58aed5f4c753f206b7db896046fa7d774bbc4bf7f8dc20b680a906ad4"}]}}`, result: func(c *Client) interface{} { - blockHash, err := util.Uint256DecodeStringLE("81b74dcfc3a42ef331eec2486231aba300ec9a95b024b0151214c76305d409bb") + blockHash, err := util.Uint256DecodeStringLE("75ab743487ce969792a4cb3c235d9ea5ff97af42b2646183c981437a077fbc45") if err != nil { panic(err) } - sender, err := address.StringToUint160("Ad1wDxzcRiRSryvJobNV211Tv7UUiziPXy") + sender, err := address.StringToUint160("ASW1VhcukJRrukCXRipY4BE9d9zy4mAYsR") if err != nil { panic(err) } - invocation, err := hex.DecodeString("0c40ae62dadb95b21628921adb9ee14e8c1f20d68b9d6ffba218f8e403af70126449435a53525cd6f1d1c871e64a91025866cd8a413ec70e3cde0ddf62931aa22baa0c40c3e09fc8ad46789d645240634ef40bd180e0dba75beae07a37dc2e899b68b4b3b3a67d076ea9444ed143dbb3264702914a4662ff95859d32c9b5bb5bdc9ec1d60c40b2511115482bd860d85f57103fb8cce2cb45ba8461d4e164685b426cb5df1525e6f09dd7aa23db0fec2241bde7c925e22f3cba3824ea461455515dc2a1455f5e0c40c0aee2528e7fd75a0434f4d67da58507e8d349ca29e01e7eafa9f283e8b8c05d06587db7234f111730c14c8a4bfb7a1ffd9493b9696c71e68966c6bf4a832ab7") + invocation, err := hex.DecodeString("0c40bfce1ead7d53339440bb29745eed4ad9840875de4f970950065291e7a14cbd249bfbf777d9a997c5e00bbc08e8ce9fdd2cd13c45c3585b4939599ff84c6149ff") if err != nil { panic(err) } - verification, err := hex.DecodeString("130c2102103a7f7dd016558597f7960d27c516a4394fd968b9e65155eb4b013e4040406e0c2102a7bc55fe8684e0119768d104ba30795bdcc86619e864add26156723ed185cd620c2102b3622bf4017bdfe317c58aed5f4c753f206b7db896046fa7d774bbc4bf7f8dc20c2103d90c07df63e690ce77912e10ab51acc944b66860237b608c4f8f8309e71ee699140b683073b3bb") + verification, err := hex.DecodeString("0c2102b3622bf4017bdfe317c58aed5f4c753f206b7db896046fa7d774bbc4bf7f8dc20b680a906ad4") + if err != nil { + panic(err) + } + vin, err := util.Uint256DecodeStringLE("1f08a32642a43e3f06b3b9a9355ed274c52de85a886841a2aef7edd94d1dc3f6") + if err != nil { + panic(err) + } + outAddress, err := address.StringToUint160("ASW1VhcukJRrukCXRipY4BE9d9zy4mAYsR") if err != nil { panic(err) } tx := transaction.NewContractTX() - tx.Nonce = 1237 - tx.ValidUntilBlock = 5 + tx.Nonce = 3 + tx.ValidUntilBlock = 1200 tx.Sender = sender tx.Scripts = []transaction.Witness{ { @@ -707,6 +761,21 @@ var rpcClientTestCases = map[string][]rpcClientTestCase{ VerificationScript: verification, }, } + tx.Inputs = []transaction.Input{ + { + PrevHash: vin, + PrevIndex: 0, + }, + } + tx.Outputs = []transaction.Output{ + { + AssetID: core.GoverningTokenID(), + Amount: util.Fixed8FromInt64(99999000), + ScriptHash: outAddress, + Position: 0, + }, + } + // Update hashes for correct result comparison. _ = tx.Hash() @@ -716,8 +785,8 @@ var rpcClientTestCases = map[string][]rpcClientTestCase{ SysFee: 0, NetFee: 0, Blockhash: blockHash, - Confirmations: 205, - Timestamp: uint64(1587727442), + Confirmations: 8, + Timestamp: uint64(1588259741), }, } }, diff --git a/pkg/rpc/server/server_test.go b/pkg/rpc/server/server_test.go index 2d10b8e5e..6a5ef7135 100644 --- a/pkg/rpc/server/server_test.go +++ b/pkg/rpc/server/server_test.go @@ -53,12 +53,12 @@ var rpcTestCases = map[string][]rpcTestCase{ "getapplicationlog": { { name: "positive", - params: `["953b6e5ba85dd068c2eba5afd2ffdf8ff832b3a791976e2fd896baf5737b2616"]`, + params: `["9872fd330d63d64beba7122fcc9678e7f380d2163acff6a7d4f67a3c01cd67d1"]`, result: func(e *executor) interface{} { return &result.ApplicationLog{} }, check: func(t *testing.T, e *executor, acc interface{}) { res, ok := acc.(*result.ApplicationLog) require.True(t, ok) - expectedTxHash, err := util.Uint256DecodeStringLE("953b6e5ba85dd068c2eba5afd2ffdf8ff832b3a791976e2fd896baf5737b2616") + expectedTxHash, err := util.Uint256DecodeStringLE("9872fd330d63d64beba7122fcc9678e7f380d2163acff6a7d4f67a3c01cd67d1") require.NoError(t, err) assert.Equal(t, expectedTxHash, res.TxHash) assert.Equal(t, 1, len(res.Executions)) @@ -253,7 +253,7 @@ var rpcTestCases = map[string][]rpcTestCase{ "getassetstate": { { name: "positive", - params: `["b16384a950ed01ed5fc15c03fe7b98228871cb43b1bc22d67029449fc854d104"]`, + params: `["8ef63ccd6f4ea20a93e7f4e84b2d43f778077612b241d617e42e1750cca4f2c5"]`, result: func(e *executor) interface{} { return &result.AssetState{} }, check: func(t *testing.T, e *executor, as interface{}) { res, ok := as.(*result.AssetState) @@ -472,7 +472,7 @@ var rpcTestCases = map[string][]rpcTestCase{ params: `["` + testchain.MultisigAddress() + `"]`, result: func(*executor) interface{} { // hash of the issueTx - h, _ := util.Uint256DecodeStringBE("8a4711012932f4f79f9534803feab0ef85e7a313c52a36f5d56b9f8ec190bd92") + h, _ := util.Uint256DecodeStringBE("99bd2bb2791887ddd3f64dac70ac15339956c76e7c306a1202372ff24fe30635") amount := util.Fixed8FromInt64(1 * 8) // (endHeight - startHeight) * genAmount[0] return &result.ClaimableInfo{ Spents: []result.Claimable{ @@ -531,7 +531,7 @@ var rpcTestCases = map[string][]rpcTestCase{ "gettransactionheight": { { name: "positive", - params: `["5f1e841f625d52dd3d73bbf5203f8468835353b7c476a4d367161ea959944981"]`, + params: `["1f08a32642a43e3f06b3b9a9355ed274c52de85a886841a2aef7edd94d1dc3f6"]`, result: func(e *executor) interface{} { h := 1 return &h @@ -743,7 +743,7 @@ var rpcTestCases = map[string][]rpcTestCase{ "sendrawtransaction": { { name: "positive", - params: `["80000b00000075a94799633ed955dd85a8af314a5b435ab51903b004000000011e4db58df4326140a371d0b0cabecea70226b93157dfb561c73ba8db599ebcb6010001f5bc5a9ac7b85a47be381260a06b5a1e7a667ce8f7d7c8baa5cfc6465571377a0030d3dec386230075a94799633ed955dd85a8af314a5b435ab5190301420c401b3040b6eea83bfbd555554c94e7a0e6077922769f3ac19c1183e14dfd1d6ef6a87658b5499921ac59ae2d2acac10d8f0f6147620e27616bb5b7305fb36b6ce0290c2102b3622bf4017bdfe317c58aed5f4c753f206b7db896046fa7d774bbc4bf7f8dc20b680a906ad4"]`, + params: `["80000b00000075a94799633ed955dd85a8af314a5b435ab51903b0040000000001e53e6c239e3d8441f623ea7b48cdea60c6ae0426a8bac04296002babfeafe5a4010001dcb7e70846bb5a6828205b81b579562f0e2c15f7b3badd68d485b035882fc17d0030d3dec386230075a94799633ed955dd85a8af314a5b435ab5190301420c408378eb6bdba1f14540cf2920a4d49c52327f617dc861a21d1c085346aaae2abd410e28dc6a03471a78e71246696a591b9677a71144dfba557d1c781c8c97e350290c2102b3622bf4017bdfe317c58aed5f4c753f206b7db896046fa7d774bbc4bf7f8dc20b680a906ad4"]`, result: func(e *executor) interface{} { v := true return &v @@ -890,7 +890,7 @@ func TestRPC(t *testing.T) { var res string err := json.Unmarshal(result, &res) require.NoErrorf(t, err, "could not parse response: %s", result) - assert.Equal(t, "400000000000da1745e9b549bd0bfa1a569971c77eba30cd5a4b0000000000455b7b226c616e67223a227a682d434e222c226e616d65223a22e5b08fe89a81e882a1227d2c7b226c616e67223a22656e222c226e616d65223a22416e745368617265227d5d0000c16ff28623000000da1745e9b549bd0bfa1a569971c77eba30cd5a4b00000000", res) + assert.Equal(t, "400000000000da1745e9b549bd0bfa1a569971c77eba30cd5a4b0000000000455b7b226c616e67223a227a682d434e222c226e616d65223a22e5b08fe89a81e882a1227d2c7b226c616e67223a22656e222c226e616d65223a22416e745368617265227d5d0000c16ff28623000000da1745e9b549bd0bfa1a569971c77eba30cd5a4b0000000000", res) }) t.Run("getrawtransaction 2 arguments", func(t *testing.T) { @@ -902,7 +902,7 @@ func TestRPC(t *testing.T) { var res string err := json.Unmarshal(result, &res) require.NoErrorf(t, err, "could not parse response: %s", result) - assert.Equal(t, "400000000000da1745e9b549bd0bfa1a569971c77eba30cd5a4b0000000000455b7b226c616e67223a227a682d434e222c226e616d65223a22e5b08fe89a81e882a1227d2c7b226c616e67223a22656e222c226e616d65223a22416e745368617265227d5d0000c16ff28623000000da1745e9b549bd0bfa1a569971c77eba30cd5a4b00000000", res) + assert.Equal(t, "400000000000da1745e9b549bd0bfa1a569971c77eba30cd5a4b0000000000455b7b226c616e67223a227a682d434e222c226e616d65223a22e5b08fe89a81e882a1227d2c7b226c616e67223a22656e222c226e616d65223a22416e745368617265227d5d0000c16ff28623000000da1745e9b549bd0bfa1a569971c77eba30cd5a4b0000000000", res) }) t.Run("getrawtransaction 2 arguments, verbose", func(t *testing.T) { @@ -991,7 +991,7 @@ func TestRPC(t *testing.T) { err := json.Unmarshal(res, &txOut) require.NoErrorf(t, err, "could not parse response: %s", res) assert.Equal(t, 0, txOut.N) - assert.Equal(t, "0xf5bc5a9ac7b85a47be381260a06b5a1e7a667ce8f7d7c8baa5cfc6465571377a", txOut.Asset) + assert.Equal(t, "0xdcb7e70846bb5a6828205b81b579562f0e2c15f7b3badd68d485b035882fc17d", txOut.Asset) assert.Equal(t, util.Fixed8FromInt64(100000000), txOut.Value) assert.Equal(t, testchain.MultisigAddress(), txOut.Address) }) diff --git a/pkg/rpc/server/testdata/testblocks.acc b/pkg/rpc/server/testdata/testblocks.acc index d069cd910..91f52796f 100644 Binary files a/pkg/rpc/server/testdata/testblocks.acc and b/pkg/rpc/server/testdata/testblocks.acc differ diff --git a/pkg/util/uint160.go b/pkg/util/uint160.go index 1e457d323..736d1fe78 100644 --- a/pkg/util/uint160.go +++ b/pkg/util/uint160.go @@ -5,6 +5,8 @@ import ( "encoding/json" "fmt" "strings" + + "github.com/nspcc-dev/neo-go/pkg/io" ) // Uint160Size is the size of Uint160 in bytes. @@ -131,3 +133,13 @@ func (u *Uint160) UnmarshalJSON(data []byte) (err error) { func (u Uint160) MarshalJSON() ([]byte, error) { return []byte(`"0x` + u.StringLE() + `"`), nil } + +// EncodeBinary implements Serializable interface. +func (u *Uint160) EncodeBinary(bw *io.BinWriter) { + bw.WriteBytes(u[:]) +} + +// DecodeBinary implements Serializable interface. +func (u *Uint160) DecodeBinary(br *io.BinReader) { + br.ReadBytes(u[:]) +} diff --git a/pkg/vm/context.go b/pkg/vm/context.go index 4d1b9c00e..3a799b13c 100644 --- a/pkg/vm/context.go +++ b/pkg/vm/context.go @@ -223,10 +223,14 @@ func (c *Context) String() string { return "execution context" } -// GetContextScriptHash returns script hash of the invocation stack element +// getContextScriptHash returns script hash of the invocation stack element // number n. -func (v *VM) GetContextScriptHash(n int) util.Uint160 { - ctxIface := v.Istack().Peek(n).Value() +func (v *VM) getContextScriptHash(n int) util.Uint160 { + element := v.Istack().Peek(n) + if element == nil { + return util.Uint160{} + } + ctxIface := element.Value() ctx := ctxIface.(*Context) return ctx.ScriptHash() } @@ -234,7 +238,7 @@ func (v *VM) GetContextScriptHash(n int) util.Uint160 { // PushContextScriptHash pushes to evaluation stack the script hash of the // invocation stack element number n. func (v *VM) PushContextScriptHash(n int) error { - h := v.GetContextScriptHash(n) + h := v.getContextScriptHash(n) v.Estack().PushVal(h.BytesBE()) return nil } diff --git a/pkg/vm/vm.go b/pkg/vm/vm.go index b11bfb876..573d28159 100644 --- a/pkg/vm/vm.go +++ b/pkg/vm/vm.go @@ -34,6 +34,13 @@ func newError(ip int, op opcode.Opcode, err interface{}) *errorAtInstruct { // StateMessage is a vm state message which could be used as additional info for example by cli. type StateMessage string +// ScriptHashGetter defines an interface for getting calling, entry and current script hashes. +type ScriptHashGetter interface { + GetCallingScriptHash() util.Uint160 + GetEntryScriptHash() util.Uint160 + GetCurrentScriptHash() util.Uint160 +} + const ( // MaxArraySize is the maximum array size allowed in the VM. MaxArraySize = 1024 @@ -1527,3 +1534,18 @@ func (v *VM) bytesToPublicKey(b []byte) *keys.PublicKey { } return pkey } + +// GetCallingScriptHash implements ScriptHashGetter interface +func (v *VM) GetCallingScriptHash() util.Uint160 { + return v.getContextScriptHash(1) +} + +// GetEntryScriptHash implements ScriptHashGetter interface +func (v *VM) GetEntryScriptHash() util.Uint160 { + return v.getContextScriptHash(v.Istack().Len() - 1) +} + +// GetCurrentScriptHash implements ScriptHashGetter interface +func (v *VM) GetCurrentScriptHash() util.Uint160 { + return v.getContextScriptHash(0) +}