core: move transaction's sender to cosigners

Closes #1184

Ported changes from https://github.com/neo-project/neo/pull/1752
This commit is contained in:
Anna Shaleva 2020-07-29 19:57:38 +03:00
parent 8697582b23
commit 90825efa16
36 changed files with 307 additions and 264 deletions

View file

@ -148,11 +148,13 @@ func NewCommands() []cli.Command {
{
Name: "invokefunction",
Usage: "invoke deployed contract on the blockchain",
UsageText: "neo-go contract invokefunction -r endpoint -w wallet [-a address] [-g gas] scripthash [method] [arguments...] [--] [cosigners...]",
UsageText: "neo-go contract invokefunction -r endpoint -w wallet [-a address] [-g gas] scripthash [method] [arguments...] [--] [signers...]",
Description: `Executes given (as a script hash) deployed script with the given method,
arguments and cosigners. See testinvokefunction documentation for the details
about parameters. It differs from testinvokefunction in that this command
sends an invocation transaction to the network.
arguments and signers. Sender is included in the list of signers by default
with FeeOnly witness scope. If you'd like to change default sender's scope,
specify it via signers parameter. See testinvokefunction documentation for
the details about parameters. It differs from testinvokefunction in that this
command sends an invocation transaction to the network.
`,
Action: invokeFunction,
Flags: invokeFunctionFlags,
@ -160,14 +162,15 @@ func NewCommands() []cli.Command {
{
Name: "testinvokefunction",
Usage: "invoke deployed contract on the blockchain (test mode)",
UsageText: "neo-go contract testinvokefunction -r endpoint scripthash [method] [arguments...] [--] [cosigners...]",
UsageText: "neo-go contract testinvokefunction -r endpoint scripthash [method] [arguments...] [--] [signers...]",
Description: `Executes given (as a script hash) deployed script with the given method,
arguments and cosigners. If no method is given "" is passed to the script, if
no arguments are given, an empty array is passed, if no cosigners are given,
no array will be passed. All of the given arguments are encapsulated into
array before invoking the script. The script thus should follow the regular
convention of smart contract arguments (method string and an array of other
arguments).
arguments and signers (sender is not included by default). If no method is given
"" is passed to the script, if no arguments are given, an empty array is
passed, if no signers are given no array is passed. If signers are specified,
the first one of them is treated as a sender. All of the given arguments are
encapsulated into array before invoking the script. The script thus should
follow the regular convention of smart contract arguments (method string and
an array of other arguments).
Arguments always do have regular Neo smart contract parameter types, either
specified explicitly or being inferred from the value. To specify the type
@ -224,12 +227,15 @@ func NewCommands() []cli.Command {
* '03b209fd4f53a7170ea4444e0cb0a6bb6a53c2bd016926989cf85f9b0fba17a70c' is a
key with a value of '03b209fd4f53a7170ea4444e0cb0a6bb6a53c2bd016926989cf85f9b0fba17a70c'
Cosigners represent a set of Uint160 hashes with witness scopes and are used
to verify hashes in System.Runtime.CheckWitness syscall. To specify cosigners
use cosigner[:scope] syntax where
* 'cosigner' is hex-encoded 160 bit (20 byte) LE value of cosigner's address,
Signers represent a set of Uint160 hashes with witness scopes and are used
to verify hashes in System.Runtime.CheckWitness syscall. First signer is treated
as a sender. To specify signers use signer[:scope] syntax where
* 'signer' is hex-encoded 160 bit (20 byte) LE value of signer's address,
which could have '0x' prefix.
* 'scope' is a comma-separated set of cosigner's scopes, which could be:
- 'FeeOnly' - marks transaction's sender and can be used only for the
sender. Signer with this scope can't be used during the
script execution and only pays fees for the transaction.
- 'Global' - allows this witness in all contexts. This cannot be combined
with other flags.
- 'CalledByEntry' - means that this condition must hold: EntryScriptHash
@ -240,8 +246,8 @@ func NewCommands() []cli.Command {
- 'CustomContracts' - define valid custom contract hashes for witness check.
- 'CustomGroups' - define custom pubkey for group members.
If no scopes were specified, 'Global' used as default. If no cosigners were
specified, no array will be passed. Note that scopes are properly handled by
If no scopes were specified, 'Global' used as default. If no signers were
specified, no array is passed. Note that scopes are properly handled by
neo-go RPC server only. C# implementation does not support scopes capability.
Examples:
@ -256,9 +262,10 @@ func NewCommands() []cli.Command {
{
Name: "testinvokescript",
Usage: "Invoke compiled AVM code in NEF format on the blockchain (test mode, not creating a transaction for it)",
UsageText: "neo-go contract testinvokescript -r endpoint -i input.nef [cosigners...]",
UsageText: "neo-go contract testinvokescript -r endpoint -i input.nef [signers...]",
Description: `Executes given compiled AVM instructions in NEF format with the given set of
cosigners. See testinvokefunction documentation for the details about parameters.
signers not included sender by default. See testinvokefunction documentation
for the details about parameters.
`,
Action: testInvokeScript,
Flags: testInvokeScriptFlags,
@ -389,7 +396,7 @@ func invokeInternal(ctx *cli.Context, signAndPush bool) error {
operation string
params = make([]smartcontract.Parameter, 0)
paramsStart = 1
cosigners []transaction.Cosigner
cosigners []transaction.Signer
cosignersStart = 0
resp *result.Invoke
acc *wallet.Account
@ -493,14 +500,14 @@ func testInvokeScript(ctx *cli.Context) error {
}
args := ctx.Args()
var cosigners []transaction.Cosigner
var signers []transaction.Signer
if args.Present() {
for i, c := range args[:] {
cosigner, err := parseCosigner(c)
if err != nil {
return cli.NewExitError(fmt.Errorf("failed to parse cosigner #%d: %v", i+1, err), 1)
return cli.NewExitError(fmt.Errorf("failed to parse signer #%d: %v", i+1, err), 1)
}
cosigners = append(cosigners, cosigner)
signers = append(signers, cosigner)
}
}
@ -512,7 +519,7 @@ func testInvokeScript(ctx *cli.Context) error {
return err
}
resp, err := c.InvokeScript(nefFile.Script, cosigners)
resp, err := c.InvokeScript(nefFile.Script, signers)
if err != nil {
return cli.NewExitError(err, 1)
}
@ -659,7 +666,7 @@ func contractDeploy(ctx *cli.Context) error {
if err != nil {
return cli.NewExitError(fmt.Errorf("failed to create deployment script: %v", err), 1)
}
// It doesn't require any cosigners.
// It doesn't require any signers.
invRes, err := c.InvokeScript(txScript, nil)
if err != nil {
return cli.NewExitError(fmt.Errorf("failed to test-invoke deployment script: %v", err), 1)
@ -687,10 +694,10 @@ func parseContractConfig(confFile string) (ProjectConfig, error) {
return conf, nil
}
func parseCosigner(c string) (transaction.Cosigner, error) {
func parseCosigner(c string) (transaction.Signer, error) {
var (
err error
res = transaction.Cosigner{
res = transaction.Signer{
Scopes: transaction.Global,
}
)
@ -706,7 +713,7 @@ func parseCosigner(c string) (transaction.Cosigner, error) {
if len(data) > 1 {
res.Scopes, err = transaction.ScopesFromString(data[1])
if err != nil {
return transaction.Cosigner{}, err
return transaction.Signer{}, err
}
}
return res, nil

View file

@ -13,7 +13,7 @@ Currently supported events:
Filters: primary ID.
* new transaction in the block
Contents: transaction.
Filters: sender and cosigner.
Filters: sender and signer.
* notification generated during execution
Contents: container hash, contract script hash, stack item.
Filters: contract script hash.
@ -57,8 +57,8 @@ Recognized stream names:
ConsensusData.
* `transaction_added`
Filter: `sender` field containing string with hex-encoded Uint160 (LE
representation) for transaction's `Sender` and/or `cosigner` in the same
format for one of transaction's `Cosigners`.
representation) for transaction's `Sender` and/or `signer` in the same
format for one of transaction's `Signers`.
* `notification_from_execution`
Filter: `contract` field containing string with hex-encoded Uint160 (LE
representation).
@ -203,7 +203,7 @@ Example:
"sysfee" : "0",
"type" : "InvocationTransaction",
"nonce" : 9,
"cosigners" : [
"signers" : [
{
"scopes" : 1,
"account" : "0x870958fd19ee3f6c7dc3c2df399d013910856e31"
@ -262,7 +262,7 @@ Example:
"nonce" : 9,
"vin" : [],
"type" : "InvocationTransaction",
"cosigners" : [
"signers" : [
{
"account" : "0x870958fd19ee3f6c7dc3c2df399d013910856e31",
"scopes" : 1

View file

@ -80,7 +80,12 @@ func getTX(t *testing.B, wif *keys.WIF) *transaction.Transaction {
tx := transaction.New(netmode.UnitTestNet, []byte{0x51}, 1)
tx.Version = 0
tx.Sender = fromAddressHash
tx.Signers = []transaction.Signer{
{
Account: fromAddressHash,
Scopes: transaction.FeeOnly,
},
}
tx.Attributes = append(tx.Attributes,
transaction.Attribute{
Usage: transaction.DescriptionURL,

View file

@ -246,7 +246,11 @@ var neoOwner = testchain.MultisigScriptHash()
func addSender(t *testing.T, txs ...*transaction.Transaction) {
for _, tx := range txs {
tx.Sender = neoOwner
tx.Signers = []transaction.Signer{
{
Account: neoOwner,
},
}
}
}

View file

@ -1226,7 +1226,7 @@ func (bc *Blockchain) verifyTx(t *transaction.Transaction, block *block.Block) e
if maxBlockSystemFee < t.SystemFee {
return errors.Errorf("policy check failed: transaction's fee shouldn't exceed maximum block system fee %d", maxBlockSystemFee)
}
balance := bc.GetUtilityTokenBalance(t.Sender)
balance := bc.GetUtilityTokenBalance(t.Sender())
need := t.SystemFee + t.NetworkFee
if balance.Cmp(big.NewInt(need)) < 0 {
return errors.Errorf("insufficient funds: balance is %v, need: %v", balance, need)
@ -1415,15 +1415,9 @@ func (bc *Blockchain) GetEnrollments() ([]state.Validator, error) {
// to verify whether the transaction is bonafide or not.
// Golang implementation of GetScriptHashesForVerifying method in C# (https://github.com/neo-project/neo/blob/master/neo/Network/P2P/Payloads/Transaction.cs#L190)
func (bc *Blockchain) GetScriptHashesForVerifying(t *transaction.Transaction) ([]util.Uint160, error) {
hashes := make(map[util.Uint160]bool)
hashes[t.Sender] = true
for _, c := range t.Cosigners {
hashes[c.Account] = true
}
// convert hashes to []util.Uint160
hashesResult := make([]util.Uint160, 0, len(hashes))
for h := range hashes {
hashesResult = append(hashesResult, h)
hashesResult := make([]util.Uint160, len(t.Signers))
for i, s := range t.Signers {
hashesResult[i] = s.Account
}
return hashesResult, nil

View file

@ -107,7 +107,7 @@ func TestGetHeader(t *testing.T) {
bc := newTestChain(t)
tx := transaction.New(netmode.UnitTestNet, []byte{byte(opcode.PUSH1)}, 0)
tx.ValidUntilBlock = bc.BlockHeight() + 1
assert.Nil(t, addSender(tx))
addSigners(tx)
assert.Nil(t, signTx(bc, tx))
block := bc.newBlock(tx)
err := bc.AddBlock(block)
@ -276,7 +276,7 @@ func TestSubscriptions(t *testing.T) {
emit.Syscall(script.BinWriter, "System.Runtime.Notify")
require.NoError(t, script.Err)
txGood1 := transaction.New(netmode.UnitTestNet, script.Bytes(), 0)
txGood1.Sender = neoOwner
txGood1.Signers = []transaction.Signer{{Account: neoOwner}}
txGood1.Nonce = 1
txGood1.ValidUntilBlock = 100500
require.NoError(t, signTx(bc, txGood1))
@ -288,7 +288,7 @@ func TestSubscriptions(t *testing.T) {
emit.Opcode(script.BinWriter, opcode.THROW)
require.NoError(t, script.Err)
txBad := transaction.New(netmode.UnitTestNet, script.Bytes(), 0)
txBad.Sender = neoOwner
txBad.Signers = []transaction.Signer{{Account: neoOwner}}
txBad.Nonce = 2
txBad.ValidUntilBlock = 100500
require.NoError(t, signTx(bc, txBad))
@ -298,7 +298,7 @@ func TestSubscriptions(t *testing.T) {
emit.Syscall(script.BinWriter, "System.Runtime.Notify")
require.NoError(t, script.Err)
txGood2 := transaction.New(netmode.UnitTestNet, script.Bytes(), 0)
txGood2.Sender = neoOwner
txGood2.Signers = []transaction.Signer{{Account: neoOwner}}
txGood2.Nonce = 3
txGood2.ValidUntilBlock = 100500
require.NoError(t, signTx(bc, txGood2))

View file

@ -190,8 +190,7 @@ func TestCreateBasicChain(t *testing.T) {
txMoveNeo := newNEP5Transfer(neoHash, neoOwner, priv0ScriptHash, neoAmount)
txMoveNeo.ValidUntilBlock = validUntilBlock
txMoveNeo.Nonce = getNextNonce()
txMoveNeo.Sender = neoOwner
txMoveNeo.Cosigners = []transaction.Cosigner{{
txMoveNeo.Signers = []transaction.Signer{{
Account: neoOwner,
Scopes: transaction.CalledByEntry,
AllowedContracts: nil,
@ -202,8 +201,7 @@ func TestCreateBasicChain(t *testing.T) {
txMoveGas := newNEP5Transfer(gasHash, neoOwner, priv0ScriptHash, int64(util.Fixed8FromInt64(1000)))
txMoveGas.ValidUntilBlock = validUntilBlock
txMoveGas.Nonce = getNextNonce()
txMoveGas.Sender = neoOwner
txMoveGas.Cosigners = []transaction.Cosigner{{
txMoveGas.Signers = []transaction.Signer{{
Account: neoOwner,
Scopes: transaction.CalledByEntry,
AllowedContracts: nil,
@ -212,8 +210,14 @@ func TestCreateBasicChain(t *testing.T) {
require.NoError(t, signTx(bc, txMoveGas))
b := bc.newBlock(txMoveNeo, txMoveGas)
require.NoError(t, bc.AddBlock(b))
t.Logf("txMoveNeo: %s", txMoveNeo.Hash().StringLE())
t.Logf("txMoveGas: %s", txMoveGas.Hash().StringLE())
t.Logf("Block1 hash: %s", b.Hash().StringLE())
bw := io.NewBufBinWriter()
b.EncodeBinary(bw.BinWriter)
require.NoError(t, bw.Err)
t.Logf("Block1 hex: %s", bw.Bytes())
t.Logf("txMoveNeo hash: %s", txMoveNeo.Hash().StringLE())
t.Logf("txMoveNeo hex: %s", hex.EncodeToString(txMoveNeo.Bytes()))
t.Logf("txMoveGas hash: %s", txMoveGas.Hash().StringLE())
require.True(t, bc.GetUtilityTokenBalance(priv0ScriptHash).Cmp(big.NewInt(1000*native.GASFactor)) >= 0)
// info for getblockheader rpc tests
@ -245,12 +249,13 @@ func TestCreateBasicChain(t *testing.T) {
txDeploy := transaction.New(testchain.Network(), txScript, 100*native.GASFactor)
txDeploy.Nonce = getNextNonce()
txDeploy.ValidUntilBlock = validUntilBlock
txDeploy.Sender = priv0ScriptHash
txDeploy.Signers = []transaction.Signer{{Account: priv0ScriptHash}}
require.NoError(t, addNetworkFee(bc, txDeploy, acc0))
require.NoError(t, acc0.SignTx(txDeploy))
b = bc.newBlock(txDeploy)
require.NoError(t, bc.AddBlock(b))
t.Logf("txDeploy: %s", txDeploy.Hash().StringLE())
t.Logf("Block2 hash: %s", b.Hash().StringLE())
// Now invoke this contract.
script = io.NewBufBinWriter()
@ -259,7 +264,7 @@ func TestCreateBasicChain(t *testing.T) {
txInv := transaction.New(testchain.Network(), script.Bytes(), 1*native.GASFactor)
txInv.Nonce = getNextNonce()
txInv.ValidUntilBlock = validUntilBlock
txInv.Sender = priv0ScriptHash
txInv.Signers = []transaction.Signer{{Account: priv0ScriptHash}}
require.NoError(t, addNetworkFee(bc, txInv, acc0))
require.NoError(t, acc0.SignTx(txInv))
b = bc.newBlock(txInv)
@ -270,8 +275,7 @@ func TestCreateBasicChain(t *testing.T) {
txNeo0to1 := newNEP5Transfer(neoHash, priv0ScriptHash, priv1.GetScriptHash(), 1000)
txNeo0to1.Nonce = getNextNonce()
txNeo0to1.ValidUntilBlock = validUntilBlock
txNeo0to1.Sender = priv0ScriptHash
txNeo0to1.Cosigners = []transaction.Cosigner{
txNeo0to1.Signers = []transaction.Signer{
{
Account: priv0ScriptHash,
Scopes: transaction.CalledByEntry,
@ -290,14 +294,13 @@ func TestCreateBasicChain(t *testing.T) {
initTx := transaction.New(testchain.Network(), w.Bytes(), 1*native.GASFactor)
initTx.Nonce = getNextNonce()
initTx.ValidUntilBlock = validUntilBlock
initTx.Sender = priv0ScriptHash
initTx.Signers = []transaction.Signer{{Account: priv0ScriptHash}}
require.NoError(t, addNetworkFee(bc, initTx, acc0))
require.NoError(t, acc0.SignTx(initTx))
transferTx := newNEP5Transfer(sh, sh, priv0.GetScriptHash(), 1000)
transferTx.Nonce = getNextNonce()
transferTx.ValidUntilBlock = validUntilBlock
transferTx.Sender = priv0ScriptHash
transferTx.Cosigners = []transaction.Cosigner{
transferTx.Signers = []transaction.Signer{
{
Account: priv0ScriptHash,
Scopes: transaction.CalledByEntry,
@ -315,8 +318,7 @@ func TestCreateBasicChain(t *testing.T) {
transferTx = newNEP5Transfer(sh, priv0.GetScriptHash(), priv1.GetScriptHash(), 123)
transferTx.Nonce = getNextNonce()
transferTx.ValidUntilBlock = validUntilBlock
transferTx.Sender = priv0ScriptHash
transferTx.Cosigners = []transaction.Cosigner{
transferTx.Signers = []transaction.Signer{
{
Account: priv0ScriptHash,
Scopes: transaction.CalledByEntry,
@ -357,8 +359,7 @@ func TestCreateBasicChain(t *testing.T) {
txSendRaw := newNEP5Transfer(neoHash, priv0ScriptHash, priv1.GetScriptHash(), int64(util.Fixed8FromInt64(1000)))
txSendRaw.ValidUntilBlock = validUntilBlock
txSendRaw.Nonce = getNextNonce()
txSendRaw.Sender = priv0ScriptHash
txSendRaw.Cosigners = []transaction.Cosigner{{
txSendRaw.Signers = []transaction.Signer{{
Account: priv0ScriptHash,
Scopes: transaction.CalledByEntry,
AllowedContracts: nil,
@ -366,7 +367,7 @@ func TestCreateBasicChain(t *testing.T) {
}}
require.NoError(t, addNetworkFee(bc, txSendRaw, acc0))
require.NoError(t, acc0.SignTx(txSendRaw))
bw := io.NewBufBinWriter()
bw = io.NewBufBinWriter()
txSendRaw.EncodeBinary(bw.BinWriter)
t.Logf("sendrawtransaction: %s", hex.EncodeToString(bw.Bytes()))
}
@ -380,16 +381,9 @@ func newNEP5Transfer(sc, from, to util.Uint160, amount int64) *transaction.Trans
return transaction.New(testchain.Network(), script, 10000000)
}
func addSender(txs ...*transaction.Transaction) error {
func addSigners(txs ...*transaction.Transaction) {
for _, tx := range txs {
tx.Sender = neoOwner
}
return nil
}
func addCosigners(txs ...*transaction.Transaction) {
for _, tx := range txs {
tx.Cosigners = []transaction.Cosigner{{
tx.Signers = []transaction.Signer{{
Account: neoOwner,
Scopes: transaction.CalledByEntry,
AllowedContracts: nil,
@ -424,7 +418,7 @@ func addNetworkFee(bc *Blockchain, tx *transaction.Transaction, sender *wallet.A
netFee, sizeDelta := CalculateNetworkFee(sender.Contract.Script)
tx.NetworkFee += netFee
size += sizeDelta
for _, cosigner := range tx.Cosigners {
for _, cosigner := range tx.Signers {
contract := bc.GetContractState(cosigner.Account)
if contract != nil {
netFee, sizeDelta = CalculateNetworkFee(contract.Script)

View file

@ -23,7 +23,7 @@ func CheckHashedWitness(ic *interop.Context, hash util.Uint160) (bool, error) {
}
func checkScope(d dao.DAO, tx *transaction.Transaction, v vm.ScriptHashGetter, hash util.Uint160) (bool, error) {
for _, c := range tx.Cosigners {
for _, c := range tx.Signers {
if c.Account == hash {
if c.Scopes == transaction.Global {
return true, nil

View file

@ -324,6 +324,7 @@ func createVMAndTX(t *testing.T) (*vm.VM, *transaction.Transaction, *interop.Con
})
tx.Attributes = attributes
tx.Signers = []transaction.Signer{{Account: util.Uint160{1, 2, 3, 4}}}
chain := newTestChain(t)
context := chain.newInteropContext(trigger.Application, dao.NewSimple(storage.NewMemoryStore(), netmode.UnitTestNet), nil, tx)
return v, tx, context, chain

View file

@ -167,7 +167,7 @@ func transactionToStackItem(t *transaction.Transaction) stackitem.Item {
stackitem.NewByteArray(t.Hash().BytesBE()),
stackitem.NewBigInteger(big.NewInt(int64(t.Version))),
stackitem.NewBigInteger(big.NewInt(int64(t.Nonce))),
stackitem.NewByteArray(t.Sender.BytesBE()),
stackitem.NewByteArray(t.Sender().BytesBE()),
stackitem.NewBigInteger(big.NewInt(int64(t.SystemFee))),
stackitem.NewBigInteger(big.NewInt(int64(t.NetworkFee))),
stackitem.NewBigInteger(big.NewInt(int64(t.ValidUntilBlock))),

View file

@ -39,7 +39,7 @@ func TestBCGetTransaction(t *testing.T) {
require.Equal(t, tx.Hash().BytesBE(), actual[0].Value().([]byte))
require.Equal(t, int64(tx.Version), actual[1].Value().(*big.Int).Int64())
require.Equal(t, int64(tx.Nonce), actual[2].Value().(*big.Int).Int64())
require.Equal(t, tx.Sender.BytesBE(), actual[3].Value().([]byte))
require.Equal(t, tx.Sender().BytesBE(), actual[3].Value().([]byte))
require.Equal(t, int64(tx.SystemFee), actual[4].Value().(*big.Int).Int64())
require.Equal(t, int64(tx.NetworkFee), actual[5].Value().(*big.Int).Int64())
require.Equal(t, int64(tx.ValidUntilBlock), actual[6].Value().(*big.Int).Int64())

View file

@ -109,16 +109,16 @@ func (mp *Pool) containsKey(hash util.Uint256) bool {
// tryAddSendersFee tries to add system fee and network fee to the total sender`s fee in mempool
// and returns false if both balance check is required and sender has not enough GAS to pay
func (mp *Pool) tryAddSendersFee(tx *transaction.Transaction, feer Feer, needCheck bool) bool {
senderFee, ok := mp.fees[tx.Sender]
senderFee, ok := mp.fees[tx.Sender()]
if !ok {
senderFee.balance = feer.GetUtilityTokenBalance(tx.Sender)
mp.fees[tx.Sender] = senderFee
senderFee.balance = feer.GetUtilityTokenBalance(tx.Sender())
mp.fees[tx.Sender()] = senderFee
}
if needCheck && !checkBalance(tx, senderFee) {
return false
}
senderFee.feeSum += tx.SystemFee + tx.NetworkFee
mp.fees[tx.Sender] = senderFee
mp.fees[tx.Sender()] = senderFee
return true
}
@ -199,9 +199,9 @@ func (mp *Pool) Remove(hash util.Uint256) {
} else if num == len(mp.verifiedTxes)-1 {
mp.verifiedTxes = mp.verifiedTxes[:num]
}
senderFee := mp.fees[it.txn.Sender]
senderFee := mp.fees[it.txn.Sender()]
senderFee.feeSum -= it.txn.SystemFee + it.txn.NetworkFee
mp.fees[it.txn.Sender] = senderFee
mp.fees[it.txn.Sender()] = senderFee
}
updateMempoolMetrics(len(mp.verifiedTxes))
mp.lock.Unlock()
@ -284,9 +284,9 @@ func (mp *Pool) GetVerifiedTransactions() []*transaction.Transaction {
// checkTxConflicts is an internal unprotected version of Verify.
func (mp *Pool) checkTxConflicts(tx *transaction.Transaction, fee Feer) bool {
senderFee, ok := mp.fees[tx.Sender]
senderFee, ok := mp.fees[tx.Sender()]
if !ok {
senderFee.balance = fee.GetUtilityTokenBalance(tx.Sender)
senderFee.balance = fee.GetUtilityTokenBalance(tx.Sender())
}
return checkBalance(tx, senderFee)
}

View file

@ -31,6 +31,7 @@ func testMemPoolAddRemoveWithFeer(t *testing.T, fs Feer) {
mp := NewMemPool(10)
tx := transaction.New(netmode.UnitTestNet, []byte{byte(opcode.PUSH1)}, 0)
tx.Nonce = 0
tx.Signers = []transaction.Signer{{Account: util.Uint160{1, 2, 3}}}
_, ok := mp.TryGetValue(tx.Hash())
require.Equal(t, false, ok)
require.NoError(t, mp.Add(tx, fs))
@ -60,6 +61,7 @@ func TestOverCapacity(t *testing.T) {
for i := 0; i < mempoolSize; i++ {
tx := transaction.New(netmode.UnitTestNet, []byte{byte(opcode.PUSH1)}, 0)
tx.Nonce = uint32(i)
tx.Signers = []transaction.Signer{{Account: util.Uint160{1, 2, 3}}}
require.NoError(t, mp.Add(tx, fs))
}
txcnt := uint32(mempoolSize)
@ -75,6 +77,7 @@ func TestOverCapacity(t *testing.T) {
})
tx.NetworkFee = 10000
tx.Nonce = txcnt
tx.Signers = []transaction.Signer{{Account: util.Uint160{1, 2, 3}}}
txcnt++
// size is 84, networkFee is 10000 => feePerByte is 119
require.NoError(t, mp.Add(tx, fs))
@ -89,6 +92,7 @@ func TestOverCapacity(t *testing.T) {
})
tx.NetworkFee = 100
tx.Nonce = txcnt
tx.Signers = []transaction.Signer{{Account: util.Uint160{1, 2, 3}}}
txcnt++
require.Error(t, mp.Add(tx, fs))
require.Equal(t, mempoolSize, mp.Count())
@ -98,6 +102,7 @@ func TestOverCapacity(t *testing.T) {
tx = transaction.New(netmode.UnitTestNet, []byte{byte(opcode.PUSH1)}, 0)
tx.Nonce = txcnt
tx.NetworkFee = 7000
tx.Signers = []transaction.Signer{{Account: util.Uint160{1, 2, 3}}}
txcnt++
// size is 51 (no attributes), networkFee is 7000 (<10000)
// => feePerByte is 137 (>119)
@ -110,6 +115,7 @@ func TestOverCapacity(t *testing.T) {
tx := transaction.New(netmode.UnitTestNet, []byte{byte(opcode.PUSH1)}, 0)
tx.NetworkFee = 8000
tx.Nonce = txcnt
tx.Signers = []transaction.Signer{{Account: util.Uint160{1, 2, 3}}}
txcnt++
require.NoError(t, mp.Add(tx, fs))
require.Equal(t, mempoolSize, mp.Count())
@ -119,6 +125,7 @@ func TestOverCapacity(t *testing.T) {
tx = transaction.New(netmode.UnitTestNet, []byte{byte(opcode.PUSH1)}, 0)
tx.Nonce = txcnt
tx.NetworkFee = 7000
tx.Signers = []transaction.Signer{{Account: util.Uint160{1, 2, 3}}}
require.Error(t, mp.Add(tx, fs))
require.Equal(t, mempoolSize, mp.Count())
require.Equal(t, true, sort.IsSorted(sort.Reverse(mp.verifiedTxes)))
@ -133,6 +140,7 @@ func TestGetVerified(t *testing.T) {
for i := 0; i < mempoolSize; i++ {
tx := transaction.New(netmode.UnitTestNet, []byte{byte(opcode.PUSH1)}, 0)
tx.Nonce = uint32(i)
tx.Signers = []transaction.Signer{{Account: util.Uint160{1, 2, 3}}}
txes = append(txes, tx)
require.NoError(t, mp.Add(tx, fs))
}
@ -157,6 +165,7 @@ func TestRemoveStale(t *testing.T) {
for i := 0; i < mempoolSize; i++ {
tx := transaction.New(netmode.UnitTestNet, []byte{byte(opcode.PUSH1)}, 0)
tx.Nonce = uint32(i)
tx.Signers = []transaction.Signer{{Account: util.Uint160{1, 2, 3}}}
if i%2 == 0 {
txes1 = append(txes1, tx)
} else {
@ -186,7 +195,7 @@ func TestMemPoolFees(t *testing.T) {
sender0 := util.Uint160{1, 2, 3}
tx0 := transaction.New(netmode.UnitTestNet, []byte{byte(opcode.PUSH1)}, 0)
tx0.NetworkFee = balance.Int64() + 1
tx0.Sender = sender0
tx0.Signers = []transaction.Signer{{Account: sender0}}
// insufficient funds to add transaction, and balance shouldn't be stored
require.Equal(t, false, mp.Verify(tx0, &FeerStub{}))
require.Error(t, mp.Add(tx0, &FeerStub{}))
@ -196,7 +205,7 @@ func TestMemPoolFees(t *testing.T) {
// no problems with adding another transaction with lower fee
tx1 := transaction.New(netmode.UnitTestNet, []byte{byte(opcode.PUSH1)}, 0)
tx1.NetworkFee = balancePart.Int64()
tx1.Sender = sender0
tx1.Signers = []transaction.Signer{{Account: sender0}}
require.NoError(t, mp.Add(tx1, &FeerStub{}))
require.Equal(t, 1, len(mp.fees))
require.Equal(t, utilityBalanceAndFees{
@ -207,7 +216,7 @@ func TestMemPoolFees(t *testing.T) {
// balance shouldn't change after adding one more transaction
tx2 := transaction.New(netmode.UnitTestNet, []byte{byte(opcode.PUSH1)}, 0)
tx2.NetworkFee = new(big.Int).Sub(balance, balancePart).Int64()
tx2.Sender = sender0
tx2.Signers = []transaction.Signer{{Account: sender0}}
require.NoError(t, mp.Add(tx2, &FeerStub{}))
require.Equal(t, 2, len(mp.verifiedTxes))
require.Equal(t, 1, len(mp.fees))
@ -219,7 +228,7 @@ func TestMemPoolFees(t *testing.T) {
// can't add more transactions as we don't have enough GAS
tx3 := transaction.New(netmode.UnitTestNet, []byte{byte(opcode.PUSH1)}, 0)
tx3.NetworkFee = 1
tx3.Sender = sender0
tx3.Signers = []transaction.Signer{{Account: sender0}}
require.Equal(t, false, mp.Verify(tx3, &FeerStub{}))
require.Error(t, mp.Add(tx3, &FeerStub{}))
require.Equal(t, 1, len(mp.fees))

View file

@ -88,7 +88,7 @@ func (g *GAS) OnPersist(ic *interop.Context) error {
}
for _, tx := range ic.Block.Transactions {
absAmount := big.NewInt(tx.SystemFee + tx.NetworkFee)
g.burn(ic, tx.Sender, absAmount)
g.burn(ic, tx.Sender(), absAmount)
}
validators, err := g.NEO.getNextBlockValidatorsInternal(ic.Chain, ic.DAO)
if err != nil {

View file

@ -115,13 +115,13 @@ func TestNativeContract_Invoke(t *testing.T) {
tx := transaction.New(chain.GetConfig().Magic, script, testSumPrice*2+10000)
validUntil := chain.blockHeight + 1
tx.ValidUntilBlock = validUntil
require.NoError(t, addSender(tx))
addSigners(tx)
require.NoError(t, signTx(chain, tx))
// Enough for Call and other opcodes, but not enough for "sum" call.
tx2 := transaction.New(chain.GetConfig().Magic, script, testSumPrice*2)
tx2.ValidUntilBlock = chain.blockHeight + 1
require.NoError(t, addSender(tx2))
addSigners(tx2)
require.NoError(t, signTx(chain, tx2))
b := chain.newBlock(tx, tx2)

View file

@ -225,12 +225,8 @@ func invokeNativePolicyMethod(chain *Blockchain, method string, args ...interfac
tx := transaction.New(chain.GetConfig().Magic, script, 10000000)
validUntil := chain.blockHeight + 1
tx.ValidUntilBlock = validUntil
err := addSender(tx)
if err != nil {
return nil, err
}
addCosigners(tx)
err = signTx(chain, tx)
addSigners(tx)
err := signTx(chain, tx)
if err != nil {
return nil, err
}

View file

@ -11,8 +11,8 @@ import (
// The maximum number of AllowedContracts or AllowedGroups
const maxSubitems = 16
// Cosigner implements a Transaction cosigner.
type Cosigner struct {
// Signer implements a Transaction signer.
type Signer struct {
Account util.Uint160 `json:"account"`
Scopes WitnessScope `json:"scopes"`
AllowedContracts []util.Uint160 `json:"allowedcontracts,omitempty"`
@ -20,7 +20,7 @@ type Cosigner struct {
}
// EncodeBinary implements Serializable interface.
func (c *Cosigner) EncodeBinary(bw *io.BinWriter) {
func (c *Signer) EncodeBinary(bw *io.BinWriter) {
bw.WriteBytes(c.Account[:])
bw.WriteB(byte(c.Scopes))
if c.Scopes&CustomContracts != 0 {
@ -32,10 +32,10 @@ func (c *Cosigner) EncodeBinary(bw *io.BinWriter) {
}
// DecodeBinary implements Serializable interface.
func (c *Cosigner) DecodeBinary(br *io.BinReader) {
func (c *Signer) DecodeBinary(br *io.BinReader) {
br.ReadBytes(c.Account[:])
c.Scopes = WitnessScope(br.ReadB())
if c.Scopes & ^(Global|CalledByEntry|CustomContracts|CustomGroups) != 0 {
if c.Scopes & ^(Global|CalledByEntry|CustomContracts|CustomGroups|FeeOnly) != 0 {
br.Err = errors.New("unknown witness scope")
return
}

View file

@ -8,21 +8,21 @@ import (
)
func TestCosignerEncodeDecode(t *testing.T) {
expected := &Cosigner{
expected := &Signer{
Account: util.Uint160{1, 2, 3, 4, 5},
Scopes: CustomContracts,
AllowedContracts: []util.Uint160{{1, 2, 3, 4}, {6, 7, 8, 9}},
}
actual := &Cosigner{}
actual := &Signer{}
testserdes.EncodeDecodeBinary(t, expected, actual)
}
func TestCosignerMarshallUnmarshallJSON(t *testing.T) {
expected := &Cosigner{
expected := &Signer{
Account: util.Uint160{1, 2, 3, 4, 5},
Scopes: CustomContracts,
AllowedContracts: []util.Uint160{{1, 2, 3, 4}, {6, 7, 8, 9}},
}
actual := &Cosigner{}
actual := &Signer{}
testserdes.MarshalUnmarshalJSON(t, expected, actual)
}

View file

@ -19,9 +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
// MaxAttributes is maximum number of attributes including signers that can be contained
// within a transaction. It is set to be 16.
MaxAttributes = 16
)
// Transaction is a process recorded in the NEO blockchain.
@ -32,9 +32,6 @@ type Transaction struct {
// Random number to avoid hash collision.
Nonce uint32
// Address signed the transaction.
Sender util.Uint160
// Fee to be burned.
SystemFee int64
@ -51,8 +48,8 @@ type Transaction struct {
// Transaction attributes.
Attributes []Attribute
// Transaction cosigners (not include Sender).
Cosigners []Cosigner
// Transaction signers list (starts with Sender).
Signers []Signer
// The scripts that comes with this transaction.
// Scripts exist out of the verification script
@ -96,7 +93,7 @@ func New(network netmode.Magic, script []byte, gas int64) *Transaction {
Script: script,
SystemFee: gas,
Attributes: []Attribute{},
Cosigners: []Cosigner{},
Signers: []Signer{},
Scripts: []Witness{},
Network: network,
}
@ -131,7 +128,6 @@ func (t *Transaction) decodeHashableFields(br *io.BinReader) {
return
}
t.Nonce = br.ReadU32LE()
t.Sender.DecodeBinary(br)
t.SystemFee = int64(br.ReadU64LE())
if t.SystemFee < 0 {
br.Err = errors.New("negative system fee")
@ -148,22 +144,25 @@ func (t *Transaction) decodeHashableFields(br *io.BinReader) {
}
t.ValidUntilBlock = br.ReadU32LE()
br.ReadArray(&t.Attributes)
br.ReadArray(&t.Cosigners, MaxCosigners)
for i := 0; i < len(t.Cosigners); i++ {
if t.Cosigners[i].Scopes == FeeOnly {
br.ReadArray(&t.Signers, MaxAttributes)
if len(t.Signers) == 0 {
br.Err = errors.New("signers array should contain sender")
return
}
for i := 0; i < len(t.Signers); i++ {
if i > 0 && t.Signers[i].Scopes == FeeOnly {
br.Err = errors.New("FeeOnly scope can be used only for sender")
return
}
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")
for j := i + 1; j < len(t.Signers); j++ {
if t.Signers[i].Account.Equals(t.Signers[j].Account) {
br.Err = errors.New("transaction signers should be unique")
return
}
}
}
br.ReadArray(&t.Attributes, MaxAttributes-len(t.Signers))
t.Script = br.ReadVarBytes()
if br.Err == nil && len(t.Script) == 0 {
br.Err = errors.New("no script")
@ -201,17 +200,11 @@ func (t *Transaction) encodeHashableFields(bw *io.BinWriter) {
}
bw.WriteB(byte(t.Version))
bw.WriteU32LE(t.Nonce)
t.Sender.EncodeBinary(bw)
bw.WriteU64LE(uint64(t.SystemFee))
bw.WriteU64LE(uint64(t.NetworkFee))
bw.WriteU32LE(t.ValidUntilBlock)
// Attributes
bw.WriteArray(t.Signers)
bw.WriteArray(t.Attributes)
// Cosigners
bw.WriteArray(t.Cosigners)
bw.WriteVarBytes(t.Script)
}
@ -297,6 +290,15 @@ func (t *Transaction) FeePerByte() int64 {
return t.feePerByte
}
// Sender returns the sender of the transaction which is always on the first place
// in the transaction's signers list.
func (t *Transaction) Sender() util.Uint160 {
if len(t.Signers) == 0 {
panic("transaction does not have signers")
}
return t.Signers[0].Account
}
// transactionJSON is a wrapper for Transaction and
// used for correct marhalling of transaction.Data
type transactionJSON struct {
@ -309,7 +311,7 @@ type transactionJSON struct {
NetworkFee int64 `json:"netfee,string"`
ValidUntilBlock uint32 `json:"validuntilblock"`
Attributes []Attribute `json:"attributes"`
Cosigners []Cosigner `json:"cosigners"`
Signers []Signer `json:"signers"`
Script []byte `json:"script"`
Scripts []Witness `json:"witnesses"`
}
@ -321,10 +323,10 @@ func (t *Transaction) MarshalJSON() ([]byte, error) {
Size: io.GetVarSize(t),
Version: t.Version,
Nonce: t.Nonce,
Sender: address.Uint160ToString(t.Sender),
Sender: address.Uint160ToString(t.Sender()),
ValidUntilBlock: t.ValidUntilBlock,
Attributes: t.Attributes,
Cosigners: t.Cosigners,
Signers: t.Signers,
Script: t.Script,
Scripts: t.Scripts,
SystemFee: t.SystemFee,
@ -343,15 +345,10 @@ func (t *Transaction) UnmarshalJSON(data []byte) error {
t.Nonce = tx.Nonce
t.ValidUntilBlock = tx.ValidUntilBlock
t.Attributes = tx.Attributes
t.Cosigners = tx.Cosigners
t.Signers = tx.Signers
t.Scripts = tx.Scripts
t.SystemFee = tx.SystemFee
t.NetworkFee = tx.NetworkFee
sender, err := address.StringToUint160(tx.Sender)
if err != nil {
return errors.New("cannot unmarshal tx: bad sender")
}
t.Sender = sender
t.Script = tx.Script
if t.Hash() != tx.TxID {
return errors.New("txid doesn't match transaction hash")

View file

@ -6,6 +6,7 @@ import (
"github.com/nspcc-dev/neo-go/pkg/config/netmode"
"github.com/nspcc-dev/neo-go/pkg/internal/testserdes"
"github.com/nspcc-dev/neo-go/pkg/util"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
@ -64,6 +65,7 @@ func TestDecodeEncodeInvocationTX(t *testing.T) {
func TestNew(t *testing.T) {
script := []byte{0x51}
tx := New(netmode.UnitTestNet, script, 1)
tx.Signers = []Signer{{Account: util.Uint160{1, 2, 3}}}
assert.Equal(t, int64(1), tx.SystemFee)
assert.Equal(t, script, tx.Script)
// Update hash fields to match tx2 that is gonna autoupdate them on decode.
@ -75,6 +77,7 @@ func TestNewTransactionFromBytes(t *testing.T) {
script := []byte{0x51}
tx := New(netmode.UnitTestNet, script, 1)
tx.NetworkFee = 123
tx.Signers = []Signer{{Account: util.Uint160{1, 2, 3}}}
data, err := testserdes.EncodeBinary(tx)
require.NoError(t, err)
@ -106,6 +109,7 @@ func TestDecodingTXWithNoScript(t *testing.T) {
func TestMarshalUnmarshalJSONInvocationTX(t *testing.T) {
tx := &Transaction{
Version: 0,
Signers: []Signer{{Account: util.Uint160{1, 2, 3}}},
Script: []byte{1, 2, 3, 4},
Attributes: []Attribute{},
Scripts: []Witness{},

View file

@ -7,7 +7,7 @@ import (
"strings"
)
// WitnessScope represents set of witness flags for Transaction cosigner.
// WitnessScope represents set of witness flags for Transaction signer.
type WitnessScope byte
const (

View file

@ -78,7 +78,12 @@ func deployNativeContracts(magic netmode.Magic) *transaction.Transaction {
script := buf.Bytes()
tx := transaction.New(magic, script, 0)
tx.Nonce = 0
tx.Sender = hash.Hash160([]byte{byte(opcode.PUSH1)})
tx.Signers = []transaction.Signer{
{
Account: hash.Hash160([]byte{byte(opcode.PUSH1)}),
Scopes: transaction.FeeOnly,
},
}
tx.Scripts = []transaction.Witness{
{
InvocationScript: []byte{},

View file

@ -21,7 +21,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 := "94e61af2441145cc251752707a58107850328a48bb095fd175ca2f8513ab5676"
expect := "ecaee33262f1bc7c7c28f2b25b54a5d61d50670871f45c0c6fe755a40cbde4a8"
assert.Equal(t, expect, block.Hash().StringLE())
}

View file

@ -131,7 +131,7 @@ func (c *Client) CreateNEP5MultiTransferTx(acc *wallet.Account, token util.Uint1
}
script := w.Bytes()
result, err := c.InvokeScript(script, []transaction.Cosigner{
result, err := c.InvokeScript(script, []transaction.Signer{
{
Account: from,
Scopes: transaction.CalledByEntry,
@ -141,8 +141,7 @@ func (c *Client) CreateNEP5MultiTransferTx(acc *wallet.Account, token util.Uint1
return nil, fmt.Errorf("can't add system fee to transaction: %v", err)
}
tx := transaction.New(c.opts.Network, script, result.GasConsumed)
tx.Sender = from
tx.Cosigners = []transaction.Cosigner{
tx.Signers = []transaction.Signer{
{
Account: from,
Scopes: transaction.CalledByEntry,

View file

@ -345,31 +345,31 @@ func (c *Client) GetVersion() (*result.Version, error) {
// InvokeScript returns the result of the given script after running it true the VM.
// NOTE: This is a test invoke and will not affect the blockchain.
func (c *Client) InvokeScript(script []byte, cosigners []transaction.Cosigner) (*result.Invoke, error) {
func (c *Client) InvokeScript(script []byte, signers []transaction.Signer) (*result.Invoke, error) {
var p = request.NewRawParams(hex.EncodeToString(script))
return c.invokeSomething("invokescript", p, cosigners)
return c.invokeSomething("invokescript", p, signers)
}
// InvokeFunction returns the results after calling the smart contract scripthash
// with the given operation and parameters.
// NOTE: this is test invoke and will not affect the blockchain.
func (c *Client) InvokeFunction(contract util.Uint160, operation string, params []smartcontract.Parameter, cosigners []transaction.Cosigner) (*result.Invoke, error) {
func (c *Client) InvokeFunction(contract util.Uint160, operation string, params []smartcontract.Parameter, signers []transaction.Signer) (*result.Invoke, error) {
var p = request.NewRawParams(contract.StringLE(), operation, params)
return c.invokeSomething("invokefunction", p, cosigners)
return c.invokeSomething("invokefunction", p, signers)
}
// invokeSomething is an inner wrapper for Invoke* functions
func (c *Client) invokeSomething(method string, p request.RawParams, cosigners []transaction.Cosigner) (*result.Invoke, error) {
func (c *Client) invokeSomething(method string, p request.RawParams, signers []transaction.Signer) (*result.Invoke, error) {
var resp = new(result.Invoke)
if cosigners != nil {
p.Values = append(p.Values, cosigners)
if signers != nil {
p.Values = append(p.Values, signers)
}
if err := c.performRequest(method, p, resp); err != nil {
// Retry with old-fashioned hashes (see neo/neo-modules#260).
if cosigners != nil {
var hashes = make([]util.Uint160, len(cosigners))
for i := range cosigners {
hashes[i] = cosigners[i].Account
if signers != nil {
var hashes = make([]util.Uint160, len(signers))
for i := range signers {
hashes[i] = signers[i].Account
}
p.Values[len(p.Values)-1] = hashes
err = c.performRequest(method, p, resp)
@ -419,13 +419,18 @@ func (c *Client) SubmitBlock(b block.Block) (util.Uint256, error) {
// SignAndPushInvocationTx signs and pushes given script as an invocation
// transaction using given wif to sign it and spending the amount of gas
// specified. It returns a hash of the invocation transaction and an error.
func (c *Client) SignAndPushInvocationTx(script []byte, acc *wallet.Account, sysfee int64, netfee util.Fixed8, cosigners []transaction.Cosigner) (util.Uint256, error) {
func (c *Client) SignAndPushInvocationTx(script []byte, acc *wallet.Account, sysfee int64, netfee util.Fixed8, cosigners []transaction.Signer) (util.Uint256, error) {
var txHash util.Uint256
var err error
tx := transaction.New(c.opts.Network, script, sysfee)
tx.SystemFee = sysfee
tx.Cosigners = cosigners
addr, err := address.StringToUint160(acc.Address)
if err != nil {
return txHash, errors.Wrap(err, "failed to get address")
}
tx.Signers = getSigners(addr, cosigners)
validUntilBlock, err := c.CalculateValidUntilBlock()
if err != nil {
@ -433,12 +438,6 @@ func (c *Client) SignAndPushInvocationTx(script []byte, acc *wallet.Account, sys
}
tx.ValidUntilBlock = validUntilBlock
addr, err := address.StringToUint160(acc.Address)
if err != nil {
return txHash, errors.Wrap(err, "failed to get address")
}
tx.Sender = addr
err = c.AddNetworkFee(tx, int64(netfee), acc)
if err != nil {
return txHash, errors.Wrapf(err, "failed to add network fee")
@ -458,6 +457,27 @@ func (c *Client) SignAndPushInvocationTx(script []byte, acc *wallet.Account, sys
return txHash, nil
}
// getSigners returns an array of transaction signers from given sender and cosigners.
// If cosigners list already contains sender, the sender will be placed at the start of
// the list.
func getSigners(sender util.Uint160, cosigners []transaction.Signer) []transaction.Signer {
s := transaction.Signer{
Account: sender,
Scopes: transaction.FeeOnly,
}
for i, c := range cosigners {
if c.Account == sender {
if i == 0 {
return cosigners
}
s.Scopes = c.Scopes
cosigners = append(cosigners[:i], cosigners[i+1:]...)
break
}
}
return append([]transaction.Signer{s}, cosigners...)
}
// ValidateAddress verifies that the address is a correct NEO address.
func (c *Client) ValidateAddress(address string) error {
var (
@ -513,7 +533,7 @@ func (c *Client) AddNetworkFee(tx *transaction.Transaction, extraFee int64, acc
tx.NetworkFee += netFee
size += sizeDelta
}
for _, cosigner := range tx.Cosigners {
for _, cosigner := range tx.Signers {
script := acc.Contract.Script
if !cosigner.Account.Equals(hash.Hash160(acc.Contract.Script)) {
contract, err := c.GetContractState(cosigner.Account)

View file

@ -41,17 +41,17 @@ type rpcClientTestCase struct {
check func(t *testing.T, c *Client, result interface{})
}
const hexB1 = "000000008aaab19c43c4ca2870c3e616b123f1b689866f44b138ae4d6a5352e54442fd56401107247de4e35599d1feffaf6e763972f738d2858b0a22ad06523867e4dcf921f7c1c67201000001000000abec5362f11e75b6e02e407bb98d63675d14384101fd08010c400f01eb6371a135527ddb205a0dae1f69d2d324837cce128bead9033091883f9ce21e6d759a40f690746592b021d397f088e3b7b417fcef73cd1bfdc2800769520c4084f7ae5d9f58a09aa56eeb2f282744a59a82d17e3be0eb1c7f54e6e8df79620e2608191bac57280a836db2ec2a776d07e43f16bc76c47d348b0fcd09d56c7c320c402b95b4e39ec35162a640795ff223e92dec95390a072eb457f6a4323052f80731517e0df029e4a457204f777f5261c6a4a88d46d4c3abdec635a6eed580d6c77f0c40b9735745b1dd795a258c31d8e6fa87d5cfc2e9b3a4890d610d33bcf833b64c58b0c5cea17f3a7128f1065ed193e636971590f193f28bdd1eeebbbc1fe6e7cee594130c2102103a7f7dd016558597f7960d27c516a4394fd968b9e65155eb4b013e4040406e0c2102a7bc55fe8684e0119768d104ba30795bdcc86619e864add26156723ed185cd620c2102b3622bf4017bdfe317c58aed5f4c753f206b7db896046fa7d774bbc4bf7f8dc20c2103d90c07df63e690ce77912e10ab51acc944b66860237b608c4f8f8309e71ee699140b413073b3bb030057040000000000000002000000abec5362f11e75b6e02e407bb98d63675d14384100000000000000003e5f0d0000000000b00400000001abec5362f11e75b6e02e407bb98d63675d14384101590218ddf5050c14316e851039019d39dfc2c37d6c3fee19fd5809870c14abec5362f11e75b6e02e407bb98d63675d14384113c00c087472616e736665720c14897720d8cd76f4f00abfa37c0edd889c208fde9b41627d5b523801fd08010c40ae6fc04fe4b6c22218ca9617c98d607d9ec9b1faf8cfdc3391bec485ae76b11adc6cc6abeb31a50b536ea8073e674d62a5566fce5e0a0ceb0718cb971c1ae3d00c40603071b725a58d052cad7afd88e99b27baab931afd5bb50d16e224335aab450170aabe251d3c0c6ad3f31dd7e9b89b209baabe5a1e2fa588bd8118f9e2a6960f0c40d72afcf39e663dba2d70fb8c36a09d1a6a6ad0d2fd38c857a8e7dc71e2b98711324e0d2ec641fe6896ba63ba80d3ea341c1aad11e082fb188ee07e215b4031b10c409afb2808b60286a56343b7ffcef28bb2ab0c595603e7323b5e5b0b9c1c10edfa5c40754d921865cb6fd71668a206b37a1eb10c0029a9fcd3a856aed07742cd3f94130c2102103a7f7dd016558597f7960d27c516a4394fd968b9e65155eb4b013e4040406e0c2102a7bc55fe8684e0119768d104ba30795bdcc86619e864add26156723ed185cd620c2102b3622bf4017bdfe317c58aed5f4c753f206b7db896046fa7d774bbc4bf7f8dc20c2103d90c07df63e690ce77912e10ab51acc944b66860237b608c4f8f8309e71ee699140b413073b3bb0003000000abec5362f11e75b6e02e407bb98d63675d1438410000000000000000de6e0d0000000000b00400000001abec5362f11e75b6e02e407bb98d63675d143841015d0300e87648170000000c14316e851039019d39dfc2c37d6c3fee19fd5809870c14abec5362f11e75b6e02e407bb98d63675d14384113c00c087472616e736665720c143b7d3711c6f0ccf9b1dca903d1bfa1d896f1238c41627d5b523801fd08010c408710e7b5d8ac6cd8d09d6fb35bf2dcce5f5fb38595ddb6d04a570bc925bc2c55a73cdf5f3cb5a1feb0acc4f26c8bbca6c43df3b4a98b8c3c2c809c2f096eb25a0c40c186c102cbf72313fd94df5077fc5bbefcd32227ed2159a47a46594877fa39f330d8223b45aa24aff005bebb5b2427a50c8c4de8618e7d7b00d73d836c44942e0c40a243b5b565bd4bc2f0bb112f7624f6b3514c12413c5a95230819face3f760f03fcb96b188f98038a3f251686b53a88d69744f4e4a985e6297003a80cdb169e800c404a951e61ac99d5ee31831d111754adb711b4a9060a9524fe383a90771843cdb096382674027a87f2a15a83bd77deb2b2ab1fe8b3de6e546293ef3df9b1129e2894130c2102103a7f7dd016558597f7960d27c516a4394fd968b9e65155eb4b013e4040406e0c2102a7bc55fe8684e0119768d104ba30795bdcc86619e864add26156723ed185cd620c2102b3622bf4017bdfe317c58aed5f4c753f206b7db896046fa7d774bbc4bf7f8dc20c2103d90c07df63e690ce77912e10ab51acc944b66860237b608c4f8f8309e71ee699140b413073b3bb"
const hexB1 = "00000000c0da501a765dcc77a8f2a87c4106cfc0219ff944dc66b87b228ceb95785796a40698a5fbc984182e90f519272f1364568f02f4c845e12d953a4f816d63840f2b19b10e9f73010000010000005e12bea87aeb955884f6f9ce78458cccb97c309501fd08010c400d006b6ec3bf952d536f9a911218be3ec6a94a8014885a630112d0018bcea2c5fb7643b01c68e0bcf4cfb229522e4de97d768549702bdfc7ddc2710eb70d9a820c406dc141248eeccff61f194cbd0610a7c6af4d696b39a1f2cd93b302607b9b001abc9813ffa48f0e4d08b166a3084f53bdea51843d8ead7330d31717e0deab1a7f0c40e4cad924c0979ce67e31dbe979cec6474fa4135c9b01c993965da18f54928af0278371c65b6bb31fe0c752916a92b7ad7152d96033622a85efc8ba891ffd91170c400e1fbd92d760ae03156ed17346ca3ddc80cb5a77e060871bebd7a4fdf842da5a4a51e24a36e85752b580b65e20a4cda9d74ed003d48779ad112cc5f15e29bf3794130c2102103a7f7dd016558597f7960d27c516a4394fd968b9e65155eb4b013e4040406e0c2102a7bc55fe8684e0119768d104ba30795bdcc86619e864add26156723ed185cd620c2102b3622bf4017bdfe317c58aed5f4c753f206b7db896046fa7d774bbc4bf7f8dc20c2103d90c07df63e690ce77912e10ab51acc944b66860237b608c4f8f8309e71ee699140b41138defaf03005704000000000000000200000080969800000000009e7c440000000000b0040000015e12bea87aeb955884f6f9ce78458cccb97c30950100590218ddf5050c14aa8acf859d4fe402b34e673f2156821796a488eb0c145e12bea87aeb955884f6f9ce78458cccb97c309513c00c087472616e736665720c1425059ecb4878d3a875f91c51ceded330d4575fde41627d5b523801fd08010c400871252c02d46a978b7e2047a8fa9e3e608edb03a3c6fb5c715243c86f6bcd95a325e0fba68d05454fe6e0da57710986bacdc7287389f419faf28bcd84846a460c4091e1f403af89e3a3de2617afc603e387d18e64ef7e7218c1191ecf7ae7ce81469e9fd004317e620fbcb712e187aba3da74ce0565f410e0dd3c54e69891ca54790c401c8ce4fb2631303519ca8030e45df87add8737328acc6dd6f66ac4e20eed1a7b1cb93395dc8a40358f2a494f8c248718e9d2bae0159452cde621c15d0a973fb20c4088a292b12dde29fa12c7c45ab4ed67df5ddfbeb0dd162115b3bcc267702ac9a923fccf3eb9afc4c6145cef64c7467a558a3bb2a104e8482bac2bcae58d95a0c894130c2102103a7f7dd016558597f7960d27c516a4394fd968b9e65155eb4b013e4040406e0c2102a7bc55fe8684e0119768d104ba30795bdcc86619e864add26156723ed185cd620c2102b3622bf4017bdfe317c58aed5f4c753f206b7db896046fa7d774bbc4bf7f8dc20c2103d90c07df63e690ce77912e10ab51acc944b66860237b608c4f8f8309e71ee699140b41138defaf000300000080969800000000003e8c440000000000b0040000015e12bea87aeb955884f6f9ce78458cccb97c309501005d0300e87648170000000c14aa8acf859d4fe402b34e673f2156821796a488eb0c145e12bea87aeb955884f6f9ce78458cccb97c309513c00c087472616e736665720c14bcaf41d684c7d4ad6ee0d99da9707b9d1f0c8e6641627d5b523801fd08010c408a50f97d779d365cf239eb8102d81ae8aa9376ef8b95de7d73ea40810a66d2ef5e65ce63db876e0b11232c00fd931688617619b5e9a0df36c3e2e6d901fc51380c40f3245b6cf5561cd65222bc6019652c400b3015ffde8a9f6580692ddb0c894024709286c7f3f919f736ebcccaeb6e8d8338bf2122a405fd8248dcbc558629139b0c40a423cf37a27846f5a613c704160f1b26a1fba2a284493a273f709d47f27a9412f32a01360a81d1da04e241558b0aabd33da14bff7e3e8915b303adc6acbe989a0c4084aa4ab66f9d1a11cd4d18cf43040b182c47991eb3350705f76b6b4139e783fca2ed99381ad4866882c660a62b3604e4e864ee8bb8df45258727fbf886702e6e94130c2102103a7f7dd016558597f7960d27c516a4394fd968b9e65155eb4b013e4040406e0c2102a7bc55fe8684e0119768d104ba30795bdcc86619e864add26156723ed185cd620c2102b3622bf4017bdfe317c58aed5f4c753f206b7db896046fa7d774bbc4bf7f8dc20c2103d90c07df63e690ce77912e10ab51acc944b66860237b608c4f8f8309e71ee699140b41138defaf"
const hexTxMoveNeo = "0002000000abec5362f11e75b6e02e407bb98d63675d14384100000000000000003e5f0d0000000000b00400000001abec5362f11e75b6e02e407bb98d63675d14384101590218ddf5050c14316e851039019d39dfc2c37d6c3fee19fd5809870c14abec5362f11e75b6e02e407bb98d63675d14384113c00c087472616e736665720c14897720d8cd76f4f00abfa37c0edd889c208fde9b41627d5b523801fd08010c40ae6fc04fe4b6c22218ca9617c98d607d9ec9b1faf8cfdc3391bec485ae76b11adc6cc6abeb31a50b536ea8073e674d62a5566fce5e0a0ceb0718cb971c1ae3d00c40603071b725a58d052cad7afd88e99b27baab931afd5bb50d16e224335aab450170aabe251d3c0c6ad3f31dd7e9b89b209baabe5a1e2fa588bd8118f9e2a6960f0c40d72afcf39e663dba2d70fb8c36a09d1a6a6ad0d2fd38c857a8e7dc71e2b98711324e0d2ec641fe6896ba63ba80d3ea341c1aad11e082fb188ee07e215b4031b10c409afb2808b60286a56343b7ffcef28bb2ab0c595603e7323b5e5b0b9c1c10edfa5c40754d921865cb6fd71668a206b37a1eb10c0029a9fcd3a856aed07742cd3f94130c2102103a7f7dd016558597f7960d27c516a4394fd968b9e65155eb4b013e4040406e0c2102a7bc55fe8684e0119768d104ba30795bdcc86619e864add26156723ed185cd620c2102b3622bf4017bdfe317c58aed5f4c753f206b7db896046fa7d774bbc4bf7f8dc20c2103d90c07df63e690ce77912e10ab51acc944b66860237b608c4f8f8309e71ee699140b413073b3bb"
const hexTxMoveNeo = "000200000080969800000000009e7c440000000000b0040000015e12bea87aeb955884f6f9ce78458cccb97c30950100590218ddf5050c14aa8acf859d4fe402b34e673f2156821796a488eb0c145e12bea87aeb955884f6f9ce78458cccb97c309513c00c087472616e736665720c1425059ecb4878d3a875f91c51ceded330d4575fde41627d5b523801fd08010c400871252c02d46a978b7e2047a8fa9e3e608edb03a3c6fb5c715243c86f6bcd95a325e0fba68d05454fe6e0da57710986bacdc7287389f419faf28bcd84846a460c4091e1f403af89e3a3de2617afc603e387d18e64ef7e7218c1191ecf7ae7ce81469e9fd004317e620fbcb712e187aba3da74ce0565f410e0dd3c54e69891ca54790c401c8ce4fb2631303519ca8030e45df87add8737328acc6dd6f66ac4e20eed1a7b1cb93395dc8a40358f2a494f8c248718e9d2bae0159452cde621c15d0a973fb20c4088a292b12dde29fa12c7c45ab4ed67df5ddfbeb0dd162115b3bcc267702ac9a923fccf3eb9afc4c6145cef64c7467a558a3bb2a104e8482bac2bcae58d95a0c894130c2102103a7f7dd016558597f7960d27c516a4394fd968b9e65155eb4b013e4040406e0c2102a7bc55fe8684e0119768d104ba30795bdcc86619e864add26156723ed185cd620c2102b3622bf4017bdfe317c58aed5f4c753f206b7db896046fa7d774bbc4bf7f8dc20c2103d90c07df63e690ce77912e10ab51acc944b66860237b608c4f8f8309e71ee699140b41138defaf"
const b1Verbose = `{"id":5,"jsonrpc":"2.0","result":{"size":1681,"nextblockhash":"0x45f62d72e37b074ecdc9f687222b0f91ec98d6d9af4429a2caa2e076a9196b0d","confirmations":6,"hash":"0x4f2c5539b0213ea444608cc217c5cb191255c1858ccd051ad9a36f08df26a288","version":0,"previousblockhash":"0x56fd4244e552536a4dae38b1446f8689b6f123b116e6c37028cac4439cb1aa8a","merkleroot":"0xf9dce467385206ad220a8b85d238f77239766eaffffed19955e3e47d24071140","time":1592472500001,"index":1,"nextconsensus":"Nbb1qkwcwNSBs9pAnrVVrnFbWnbWBk91U2","witnesses":[{"invocation":"DEAPAetjcaE1Un3bIFoNrh9p0tMkg3zOEovq2QMwkYg/nOIebXWaQPaQdGWSsCHTl/CI47e0F/zvc80b/cKAB2lSDECE965dn1igmqVu6y8oJ0SlmoLRfjvg6xx/VObo33liDiYIGRusVygKg22y7Cp3bQfkPxa8dsR9NIsPzQnVbHwyDEArlbTjnsNRYqZAeV/yI+kt7JU5CgcutFf2pDIwUvgHMVF+DfAp5KRXIE93f1JhxqSojUbUw6vexjWm7tWA1sd/DEC5c1dFsd15WiWMMdjm+ofVz8Lps6SJDWENM7z4M7ZMWLDFzqF/OnEo8QZe0ZPmNpcVkPGT8ovdHu67vB/m587l","verification":"EwwhAhA6f33QFlWFl/eWDSfFFqQ5T9loueZRVetLAT5AQEBuDCECp7xV/oaE4BGXaNEEujB5W9zIZhnoZK3SYVZyPtGFzWIMIQKzYiv0AXvf4xfFiu1fTHU/IGt9uJYEb6fXdLvEv3+NwgwhA9kMB99j5pDOd5EuEKtRrMlEtmhgI3tgjE+PgwnnHuaZFAtBMHOzuw=="}],"consensusdata":{"primary":0,"nonce":"0000000000000457"},"tx":[{"hash":"0x7fb05b593cf4b1eb2d9a283c5488ca1bfe61191b5775bafa43b8647e7b20f22c","size":575,"version":0,"nonce":2,"sender":"Nbb1qkwcwNSBs9pAnrVVrnFbWnbWBk91U2","sysfee":"0","netfee":"876350","validuntilblock":1200,"attributes":[],"cosigners":[{"account":"0x4138145d67638db97b402ee0b6751ef16253ecab","scopes":"CalledByEntry"}],"script":"Ahjd9QUMFDFuhRA5AZ0538LDfWw/7hn9WAmHDBSr7FNi8R51tuAuQHu5jWNnXRQ4QRPADAh0cmFuc2ZlcgwUiXcg2M129PAKv6N8Dt2InCCP3ptBYn1bUjg=","witnesses":[{"invocation":"DECub8BP5LbCIhjKlhfJjWB9nsmx+vjP3DORvsSFrnaxGtxsxqvrMaULU26oBz5nTWKlVm/OXgoM6wcYy5ccGuPQDEBgMHG3JaWNBSytev2I6ZsnuquTGv1btQ0W4iQzWqtFAXCqviUdPAxq0/Md1+m4myCbqr5aHi+liL2BGPnippYPDEDXKvzznmY9ui1w+4w2oJ0aamrQ0v04yFeo59xx4rmHETJODS7GQf5olrpjuoDT6jQcGq0R4IL7GI7gfiFbQDGxDECa+ygItgKGpWNDt//O8ouyqwxZVgPnMjteWwucHBDt+lxAdU2SGGXLb9cWaKIGs3oesQwAKan806hWrtB3Qs0/","verification":"EwwhAhA6f33QFlWFl/eWDSfFFqQ5T9loueZRVetLAT5AQEBuDCECp7xV/oaE4BGXaNEEujB5W9zIZhnoZK3SYVZyPtGFzWIMIQKzYiv0AXvf4xfFiu1fTHU/IGt9uJYEb6fXdLvEv3+NwgwhA9kMB99j5pDOd5EuEKtRrMlEtmhgI3tgjE+PgwnnHuaZFAtBMHOzuw=="}]},{"hash":"0xb661d5e4d9e41c3059b068f8abb6f1566a47ec800879e34c0ebd2799781a2760","size":579,"version":0,"nonce":3,"sender":"Nbb1qkwcwNSBs9pAnrVVrnFbWnbWBk91U2","sysfee":"0","netfee":"880350","validuntilblock":1200,"attributes":[],"cosigners":[{"account":"0x4138145d67638db97b402ee0b6751ef16253ecab","scopes":"CalledByEntry"}],"script":"AwDodkgXAAAADBQxboUQOQGdOd/Cw31sP+4Z/VgJhwwUq+xTYvEedbbgLkB7uY1jZ10UOEETwAwIdHJhbnNmZXIMFDt9NxHG8Mz5sdypA9G/odiW8SOMQWJ9W1I4","witnesses":[{"invocation":"DECHEOe12Kxs2NCdb7Nb8tzOX1+zhZXdttBKVwvJJbwsVac83188taH+sKzE8myLvKbEPfO0qYuMPCyAnC8JbrJaDEDBhsECy/cjE/2U31B3/Fu+/NMiJ+0hWaR6RllId/o58zDYIjtFqiSv8AW+u1skJ6UMjE3oYY59ewDXPYNsRJQuDECiQ7W1Zb1LwvC7ES92JPazUUwSQTxalSMIGfrOP3YPA/y5axiPmAOKPyUWhrU6iNaXRPTkqYXmKXADqAzbFp6ADEBKlR5hrJnV7jGDHREXVK23EbSpBgqVJP44OpB3GEPNsJY4JnQCeofyoVqDvXfesrKrH+iz3m5UYpPvPfmxEp4o","verification":"EwwhAhA6f33QFlWFl/eWDSfFFqQ5T9loueZRVetLAT5AQEBuDCECp7xV/oaE4BGXaNEEujB5W9zIZhnoZK3SYVZyPtGFzWIMIQKzYiv0AXvf4xfFiu1fTHU/IGt9uJYEb6fXdLvEv3+NwgwhA9kMB99j5pDOd5EuEKtRrMlEtmhgI3tgjE+PgwnnHuaZFAtBMHOzuw=="}]}]}}`
const b1Verbose = `{"id":5,"jsonrpc":"2.0","result":{"size":1641,"nextblockhash":"0x003abea54aa3c5edba7e33fb7ca96452cb65ff8cd36ce1cdfd412a6c4d3ea38a","confirmations":6,"hash":"0xd9518e322440714b0564d6f84a9a39b527b5480e4e7f7932895777a4c8fa0a9e","version":0,"previousblockhash":"0xa496577895eb8c227bb866dc44f99f21c0cf06417ca8f2a877cc5d761a50dac0","merkleroot":"0x2b0f84636d814f3a952de145c8f4028f5664132f2719f5902e1884c9fba59806","time":1596101407001,"index":1,"nextconsensus":"NUVPACMnKFhpuHjsRjhUvXz1XhqfGZYVtY","witnesses":[{"invocation":"DEANAGtuw7+VLVNvmpESGL4+xqlKgBSIWmMBEtABi86ixft2Q7AcaOC89M+yKVIuTel9doVJcCvfx93CcQ63DZqCDEBtwUEkjuzP9h8ZTL0GEKfGr01pazmh8s2TswJge5sAGryYE/+kjw5NCLFmowhPU73qUYQ9jq1zMNMXF+Deqxp/DEDkytkkwJec5n4x2+l5zsZHT6QTXJsByZOWXaGPVJKK8CeDccZba7Mf4MdSkWqSt61xUtlgM2Iqhe/Iuokf/ZEXDEAOH72S12CuAxVu0XNGyj3cgMtad+Bghxvr16T9+ELaWkpR4ko26FdStYC2XiCkzanXTtAD1Id5rREsxfFeKb83","verification":"EwwhAhA6f33QFlWFl/eWDSfFFqQ5T9loueZRVetLAT5AQEBuDCECp7xV/oaE4BGXaNEEujB5W9zIZhnoZK3SYVZyPtGFzWIMIQKzYiv0AXvf4xfFiu1fTHU/IGt9uJYEb6fXdLvEv3+NwgwhA9kMB99j5pDOd5EuEKtRrMlEtmhgI3tgjE+PgwnnHuaZFAtBE43vrw=="}],"consensusdata":{"primary":0,"nonce":"0000000000000457"},"tx":[{"hash":"0x32f9bd3a2707475407c41bf5daacf9560e25ed74f6d85b3afb2ef72edb2325ba","size":555,"version":0,"nonce":2,"sender":"NUVPACMnKFhpuHjsRjhUvXz1XhqfGZYVtY","sysfee":"10000000","netfee":"4488350","validuntilblock":1200,"attributes":[],"signers":[{"account":"0x95307cb9cc8c4578cef9f6845895eb7aa8be125e","scopes":"CalledByEntry"}],"script":"Ahjd9QUMFKqKz4WdT+QCs05nPyFWgheWpIjrDBReEr6oeuuVWIT2+c54RYzMuXwwlRPADAh0cmFuc2ZlcgwUJQWey0h406h1+RxRzt7TMNRXX95BYn1bUjg=","witnesses":[{"invocation":"DEAIcSUsAtRql4t+IEeo+p4+YI7bA6PG+1xxUkPIb2vNlaMl4PumjQVFT+bg2ldxCYa6zccoc4n0Gfryi82EhGpGDECR4fQDr4njo94mF6/GA+OH0Y5k735yGMEZHs96586BRp6f0AQxfmIPvLcS4Yero9p0zgVl9BDg3TxU5piRylR5DEAcjOT7JjEwNRnKgDDkXfh63Yc3MorMbdb2asTiDu0aexy5M5XcikA1jypJT4wkhxjp0rrgFZRSzeYhwV0Klz+yDECIopKxLd4p+hLHxFq07WffXd++sN0WIRWzvMJncCrJqSP8zz65r8TGFFzvZMdGelWKO7KhBOhIK6wryuWNlaDI","verification":"EwwhAhA6f33QFlWFl/eWDSfFFqQ5T9loueZRVetLAT5AQEBuDCECp7xV/oaE4BGXaNEEujB5W9zIZhnoZK3SYVZyPtGFzWIMIQKzYiv0AXvf4xfFiu1fTHU/IGt9uJYEb6fXdLvEv3+NwgwhA9kMB99j5pDOd5EuEKtRrMlEtmhgI3tgjE+PgwnnHuaZFAtBE43vrw=="}]},{"hash":"0xd35d6386ec2f29b90839536f6af9466098d1665e951cdd0a20db6b4629b08369","size":559,"version":0,"nonce":3,"sender":"NUVPACMnKFhpuHjsRjhUvXz1XhqfGZYVtY","sysfee":"10000000","netfee":"4492350","validuntilblock":1200,"attributes":[],"signers":[{"account":"0x95307cb9cc8c4578cef9f6845895eb7aa8be125e","scopes":"CalledByEntry"}],"script":"AwDodkgXAAAADBSqis+FnU/kArNOZz8hVoIXlqSI6wwUXhK+qHrrlViE9vnOeEWMzLl8MJUTwAwIdHJhbnNmZXIMFLyvQdaEx9StbuDZnalwe50fDI5mQWJ9W1I4","witnesses":[{"invocation":"DECKUPl9d502XPI564EC2BroqpN274uV3n1z6kCBCmbS715lzmPbh24LESMsAP2TFohhdhm16aDfNsPi5tkB/FE4DEDzJFts9VYc1lIivGAZZSxACzAV/96Kn2WAaS3bDIlAJHCShsfz+Rn3NuvMyutujYM4vyEipAX9gkjcvFWGKRObDECkI883onhG9aYTxwQWDxsmofuiooRJOic/cJ1H8nqUEvMqATYKgdHaBOJBVYsKq9M9oUv/fj6JFbMDrcasvpiaDECEqkq2b50aEc1NGM9DBAsYLEeZHrM1BwX3a2tBOeeD/KLtmTga1IZogsZgpis2BOToZO6LuN9FJYcn+/iGcC5u","verification":"EwwhAhA6f33QFlWFl/eWDSfFFqQ5T9loueZRVetLAT5AQEBuDCECp7xV/oaE4BGXaNEEujB5W9zIZhnoZK3SYVZyPtGFzWIMIQKzYiv0AXvf4xfFiu1fTHU/IGt9uJYEb6fXdLvEv3+NwgwhA9kMB99j5pDOd5EuEKtRrMlEtmhgI3tgjE+PgwnnHuaZFAtBE43vrw=="}]}]}}`
const hexHeader1 = "000000008aaab19c43c4ca2870c3e616b123f1b689866f44b138ae4d6a5352e54442fd56401107247de4e35599d1feffaf6e763972f738d2858b0a22ad06523867e4dcf921f7c1c67201000001000000abec5362f11e75b6e02e407bb98d63675d14384101fd08010c400f01eb6371a135527ddb205a0dae1f69d2d324837cce128bead9033091883f9ce21e6d759a40f690746592b021d397f088e3b7b417fcef73cd1bfdc2800769520c4084f7ae5d9f58a09aa56eeb2f282744a59a82d17e3be0eb1c7f54e6e8df79620e2608191bac57280a836db2ec2a776d07e43f16bc76c47d348b0fcd09d56c7c320c402b95b4e39ec35162a640795ff223e92dec95390a072eb457f6a4323052f80731517e0df029e4a457204f777f5261c6a4a88d46d4c3abdec635a6eed580d6c77f0c40b9735745b1dd795a258c31d8e6fa87d5cfc2e9b3a4890d610d33bcf833b64c58b0c5cea17f3a7128f1065ed193e636971590f193f28bdd1eeebbbc1fe6e7cee594130c2102103a7f7dd016558597f7960d27c516a4394fd968b9e65155eb4b013e4040406e0c2102a7bc55fe8684e0119768d104ba30795bdcc86619e864add26156723ed185cd620c2102b3622bf4017bdfe317c58aed5f4c753f206b7db896046fa7d774bbc4bf7f8dc20c2103d90c07df63e690ce77912e10ab51acc944b66860237b608c4f8f8309e71ee699140b413073b3bb00"
const hexHeader1 = "00000000c0da501a765dcc77a8f2a87c4106cfc0219ff944dc66b87b228ceb95785796a40698a5fbc984182e90f519272f1364568f02f4c845e12d953a4f816d63840f2b19b10e9f73010000010000005e12bea87aeb955884f6f9ce78458cccb97c309501fd08010c400d006b6ec3bf952d536f9a911218be3ec6a94a8014885a630112d0018bcea2c5fb7643b01c68e0bcf4cfb229522e4de97d768549702bdfc7ddc2710eb70d9a820c406dc141248eeccff61f194cbd0610a7c6af4d696b39a1f2cd93b302607b9b001abc9813ffa48f0e4d08b166a3084f53bdea51843d8ead7330d31717e0deab1a7f0c40e4cad924c0979ce67e31dbe979cec6474fa4135c9b01c993965da18f54928af0278371c65b6bb31fe0c752916a92b7ad7152d96033622a85efc8ba891ffd91170c400e1fbd92d760ae03156ed17346ca3ddc80cb5a77e060871bebd7a4fdf842da5a4a51e24a36e85752b580b65e20a4cda9d74ed003d48779ad112cc5f15e29bf3794130c2102103a7f7dd016558597f7960d27c516a4394fd968b9e65155eb4b013e4040406e0c2102a7bc55fe8684e0119768d104ba30795bdcc86619e864add26156723ed185cd620c2102b3622bf4017bdfe317c58aed5f4c753f206b7db896046fa7d774bbc4bf7f8dc20c2103d90c07df63e690ce77912e10ab51acc944b66860237b608c4f8f8309e71ee699140b41138defaf00"
const header1Verbose = `{"id":5,"jsonrpc":"2.0","result":{"hash":"0x4f2c5539b0213ea444608cc217c5cb191255c1858ccd051ad9a36f08df26a288","size":518,"version":0,"previousblockhash":"0x56fd4244e552536a4dae38b1446f8689b6f123b116e6c37028cac4439cb1aa8a","merkleroot":"0xf9dce467385206ad220a8b85d238f77239766eaffffed19955e3e47d24071140","time":1592472500001,"index":1,"nextconsensus":"Nbb1qkwcwNSBs9pAnrVVrnFbWnbWBk91U2","witnesses":[{"invocation":"DEAPAetjcaE1Un3bIFoNrh9p0tMkg3zOEovq2QMwkYg/nOIebXWaQPaQdGWSsCHTl/CI47e0F/zvc80b/cKAB2lSDECE965dn1igmqVu6y8oJ0SlmoLRfjvg6xx/VObo33liDiYIGRusVygKg22y7Cp3bQfkPxa8dsR9NIsPzQnVbHwyDEArlbTjnsNRYqZAeV/yI+kt7JU5CgcutFf2pDIwUvgHMVF+DfAp5KRXIE93f1JhxqSojUbUw6vexjWm7tWA1sd/DEC5c1dFsd15WiWMMdjm+ofVz8Lps6SJDWENM7z4M7ZMWLDFzqF/OnEo8QZe0ZPmNpcVkPGT8ovdHu67vB/m587l","verification":"EwwhAhA6f33QFlWFl/eWDSfFFqQ5T9loueZRVetLAT5AQEBuDCECp7xV/oaE4BGXaNEEujB5W9zIZhnoZK3SYVZyPtGFzWIMIQKzYiv0AXvf4xfFiu1fTHU/IGt9uJYEb6fXdLvEv3+NwgwhA9kMB99j5pDOd5EuEKtRrMlEtmhgI3tgjE+PgwnnHuaZFAtBMHOzuw=="}],"confirmations":6,"nextblockhash":"0x45f62d72e37b074ecdc9f687222b0f91ec98d6d9af4429a2caa2e076a9196b0d"}}`
const header1Verbose = `{"id":5,"jsonrpc":"2.0","result":{"hash":"0xd9518e322440714b0564d6f84a9a39b527b5480e4e7f7932895777a4c8fa0a9e","size":518,"version":0,"previousblockhash":"0xa496577895eb8c227bb866dc44f99f21c0cf06417ca8f2a877cc5d761a50dac0","merkleroot":"0x2b0f84636d814f3a952de145c8f4028f5664132f2719f5902e1884c9fba59806","time":1596101407001,"index":1,"nextconsensus":"NUVPACMnKFhpuHjsRjhUvXz1XhqfGZYVtY","witnesses":[{"invocation":"DEANAGtuw7+VLVNvmpESGL4+xqlKgBSIWmMBEtABi86ixft2Q7AcaOC89M+yKVIuTel9doVJcCvfx93CcQ63DZqCDEBtwUEkjuzP9h8ZTL0GEKfGr01pazmh8s2TswJge5sAGryYE/+kjw5NCLFmowhPU73qUYQ9jq1zMNMXF+Deqxp/DEDkytkkwJec5n4x2+l5zsZHT6QTXJsByZOWXaGPVJKK8CeDccZba7Mf4MdSkWqSt61xUtlgM2Iqhe/Iuokf/ZEXDEAOH72S12CuAxVu0XNGyj3cgMtad+Bghxvr16T9+ELaWkpR4ko26FdStYC2XiCkzanXTtAD1Id5rREsxfFeKb83","verification":"EwwhAhA6f33QFlWFl/eWDSfFFqQ5T9loueZRVetLAT5AQEBuDCECp7xV/oaE4BGXaNEEujB5W9zIZhnoZK3SYVZyPtGFzWIMIQKzYiv0AXvf4xfFiu1fTHU/IGt9uJYEb6fXdLvEv3+NwgwhA9kMB99j5pDOd5EuEKtRrMlEtmhgI3tgjE+PgwnnHuaZFAtBE43vrw=="}],"confirmations":6,"nextblockhash":"0x003abea54aa3c5edba7e33fb7ca96452cb65ff8cd36ce1cdfd412a6c4d3ea38a"}}`
const txMoveNeoVerbose = `{"id":5,"jsonrpc":"2.0","result":{"blockhash":"0x4f2c5539b0213ea444608cc217c5cb191255c1858ccd051ad9a36f08df26a288","confirmations":6,"blocktime":1592472500001,"hash":"0x7fb05b593cf4b1eb2d9a283c5488ca1bfe61191b5775bafa43b8647e7b20f22c","size":575,"version":0,"nonce":2,"sender":"Nbb1qkwcwNSBs9pAnrVVrnFbWnbWBk91U2","sysfee":"0","netfee":"876350","validuntilblock":1200,"attributes":[],"cosigners":[{"account":"0x4138145d67638db97b402ee0b6751ef16253ecab","scopes":"CalledByEntry"}],"script":"Ahjd9QUMFDFuhRA5AZ0538LDfWw/7hn9WAmHDBSr7FNi8R51tuAuQHu5jWNnXRQ4QRPADAh0cmFuc2ZlcgwUiXcg2M129PAKv6N8Dt2InCCP3ptBYn1bUjg=","witnesses":[{"invocation":"DECub8BP5LbCIhjKlhfJjWB9nsmx+vjP3DORvsSFrnaxGtxsxqvrMaULU26oBz5nTWKlVm/OXgoM6wcYy5ccGuPQDEBgMHG3JaWNBSytev2I6ZsnuquTGv1btQ0W4iQzWqtFAXCqviUdPAxq0/Md1+m4myCbqr5aHi+liL2BGPnippYPDEDXKvzznmY9ui1w+4w2oJ0aamrQ0v04yFeo59xx4rmHETJODS7GQf5olrpjuoDT6jQcGq0R4IL7GI7gfiFbQDGxDECa+ygItgKGpWNDt//O8ouyqwxZVgPnMjteWwucHBDt+lxAdU2SGGXLb9cWaKIGs3oesQwAKan806hWrtB3Qs0/","verification":"EwwhAhA6f33QFlWFl/eWDSfFFqQ5T9loueZRVetLAT5AQEBuDCECp7xV/oaE4BGXaNEEujB5W9zIZhnoZK3SYVZyPtGFzWIMIQKzYiv0AXvf4xfFiu1fTHU/IGt9uJYEb6fXdLvEv3+NwgwhA9kMB99j5pDOd5EuEKtRrMlEtmhgI3tgjE+PgwnnHuaZFAtBMHOzuw=="}]}}`
const txMoveNeoVerbose = `{"id":5,"jsonrpc":"2.0","result":{"blockhash":"0xd9518e322440714b0564d6f84a9a39b527b5480e4e7f7932895777a4c8fa0a9e","confirmations":6,"blocktime":1596101407001,"vmstate":"","hash":"0x32f9bd3a2707475407c41bf5daacf9560e25ed74f6d85b3afb2ef72edb2325ba","size":555,"version":0,"nonce":2,"sender":"NUVPACMnKFhpuHjsRjhUvXz1XhqfGZYVtY","sysfee":"10000000","netfee":"4488350","validuntilblock":1200,"attributes":[],"signers":[{"account":"0x95307cb9cc8c4578cef9f6845895eb7aa8be125e","scopes":"CalledByEntry"}],"script":"Ahjd9QUMFKqKz4WdT+QCs05nPyFWgheWpIjrDBReEr6oeuuVWIT2+c54RYzMuXwwlRPADAh0cmFuc2ZlcgwUJQWey0h406h1+RxRzt7TMNRXX95BYn1bUjg=","witnesses":[{"invocation":"DEAIcSUsAtRql4t+IEeo+p4+YI7bA6PG+1xxUkPIb2vNlaMl4PumjQVFT+bg2ldxCYa6zccoc4n0Gfryi82EhGpGDECR4fQDr4njo94mF6/GA+OH0Y5k735yGMEZHs96586BRp6f0AQxfmIPvLcS4Yero9p0zgVl9BDg3TxU5piRylR5DEAcjOT7JjEwNRnKgDDkXfh63Yc3MorMbdb2asTiDu0aexy5M5XcikA1jypJT4wkhxjp0rrgFZRSzeYhwV0Klz+yDECIopKxLd4p+hLHxFq07WffXd++sN0WIRWzvMJncCrJqSP8zz65r8TGFFzvZMdGelWKO7KhBOhIK6wryuWNlaDI","verification":"EwwhAhA6f33QFlWFl/eWDSfFFqQ5T9loueZRVetLAT5AQEBuDCECp7xV/oaE4BGXaNEEujB5W9zIZhnoZK3SYVZyPtGFzWIMIQKzYiv0AXvf4xfFiu1fTHU/IGt9uJYEb6fXdLvEv3+NwgwhA9kMB99j5pDOd5EuEKtRrMlEtmhgI3tgjE+PgwnnHuaZFAtBE43vrw=="}]}}`
// getResultBlock1 returns data for block number 1 which is used by several tests.
func getResultBlock1() *result.Block {
@ -64,14 +64,14 @@ func getResultBlock1() *result.Block {
if err != nil {
panic(err)
}
b2Hash, err := util.Uint256DecodeStringLE("45f62d72e37b074ecdc9f687222b0f91ec98d6d9af4429a2caa2e076a9196b0d")
b2Hash, err := util.Uint256DecodeStringLE("003abea54aa3c5edba7e33fb7ca96452cb65ff8cd36ce1cdfd412a6c4d3ea38a")
if err != nil {
panic(err)
}
return &result.Block{
Block: *b,
BlockMetadata: result.BlockMetadata{
Size: 1681,
Size: 1641,
NextBlockHash: &b2Hash,
Confirmations: 6,
},
@ -635,7 +635,7 @@ var rpcClientTestCases = map[string][]rpcClientTestCase{
Type: smartcontract.Hash160Type,
Value: hash,
},
}, []transaction.Cosigner{{
}, []transaction.Signer{{
Account: util.Uint160{1, 2, 3},
}})
},
@ -662,7 +662,7 @@ var rpcClientTestCases = map[string][]rpcClientTestCase{
if err != nil {
panic(err)
}
return c.InvokeScript(script, []transaction.Cosigner{{
return c.InvokeScript(script, []transaction.Signer{{
Account: util.Uint160{1, 2, 3},
}})
},

View file

@ -255,12 +255,12 @@ func (c *WSClient) SubscribeForNewBlocks(primary *int) (string, error) {
}
// SubscribeForNewTransactions adds subscription for new transaction events to
// this instance of client. It can be filtered by sender and/or cosigner, nil
// this instance of client. It can be filtered by sender and/or signer, nil
// value is treated as missing filter.
func (c *WSClient) SubscribeForNewTransactions(sender *util.Uint160, cosigner *util.Uint160) (string, error) {
func (c *WSClient) SubscribeForNewTransactions(sender *util.Uint160, signer *util.Uint160) (string, error) {
params := request.NewRawParams("transaction_added")
if sender != nil || cosigner != nil {
params.Values = append(params.Values, request.TxFilter{Sender: sender, Cosigner: cosigner})
if sender != nil || signer != nil {
params.Values = append(params.Values, request.TxFilter{Sender: sender, Signer: signer})
}
return c.performSubscription(params)
}

View file

@ -119,7 +119,7 @@ func TestWSClientEvents(t *testing.T) {
`{"jsonrpc":"2.0","method":"transaction_executed","params":[{"txid":"0xe1cd5e57e721d2a2e05fb1f08721b12057b25ab1dd7fd0f33ee1639932fdfad7","trigger":"Application","vmstate":"HALT","gasconsumed":"22910000","stack":[],"notifications":[{"contract":"0x1b4357bff5a01bdf2a6581247cf9ed1e24629176","eventname":"contract call","state":{"type":"Array","value":[{"type":"ByteString","value":"dHJhbnNmZXI="},{"type":"Array","value":[{"type":"ByteString","value":"dpFiJB7t+XwkgWUq3xug9b9XQxs="},{"type":"ByteString","value":"MW6FEDkBnTnfwsN9bD/uGf1YCYc="},{"type":"Integer","value":"1000"}]}]}},{"contract":"0x1b4357bff5a01bdf2a6581247cf9ed1e24629176","eventname":"transfer","state":{"type":"Array","value":[{"type":"ByteString","value":"dpFiJB7t+XwkgWUq3xug9b9XQxs="},{"type":"ByteString","value":"MW6FEDkBnTnfwsN9bD/uGf1YCYc="},{"type":"Integer","value":"1000"}]}}]}]}`,
`{"jsonrpc":"2.0","method":"notification_from_execution","params":[{"contract":"0x1b4357bff5a01bdf2a6581247cf9ed1e24629176","eventname":"contract call","state":{"type":"Array","value":[{"type":"ByteString","value":"dHJhbnNmZXI="},{"type":"Array","value":[{"type":"ByteString","value":"dpFiJB7t+XwkgWUq3xug9b9XQxs="},{"type":"ByteString","value":"MW6FEDkBnTnfwsN9bD/uGf1YCYc="},{"type":"Integer","value":"1000"}]}]}}]}`,
`{"jsonrpc":"2.0","method":"transaction_executed","params":[{"txid":"0xf97a72b7722c109f909a8bc16c22368c5023d85828b09b127b237aace33cf099","trigger":"Application","vmstate":"HALT","gasconsumed":"6042610","stack":[],"notifications":[{"contract":"0xe65ff7b3a02d207b584a5c27057d4e9862ef01da","eventname":"contract call","state":{"type":"Array","value":[{"type":"ByteString","value":"dHJhbnNmZXI="},{"type":"Array","value":[{"type":"ByteString","value":"MW6FEDkBnTnfwsN9bD/uGf1YCYc="},{"type":"ByteString","value":"IHKCdK+vw29DoHHTKM+j5inZy7A="},{"type":"Integer","value":"123"}]}]}},{"contract":"0xe65ff7b3a02d207b584a5c27057d4e9862ef01da","eventname":"transfer","state":{"type":"Array","value":[{"type":"ByteString","value":"MW6FEDkBnTnfwsN9bD/uGf1YCYc="},{"type":"ByteString","value":"IHKCdK+vw29DoHHTKM+j5inZy7A="},{"type":"Integer","value":"123"}]}}]}]}`,
`{"jsonrpc":"2.0","method":"block_added","params":[{"hash":"0x2d312f6379ead13cf62634c703091b750e7903728df2a3cf5bd96ce80b84a849","version":0,"previousblockhash":"0xb8237d34c156cac6be7b01578decf8ac8c99a62f0b6f774d622aad7be0fe189d","merkleroot":"0xf89169e89361692b71e671f13c088e84c5325015c413e8f89e7ba38efdb41287","time":1592472500006,"index":6,"nextconsensus":"Nbb1qkwcwNSBs9pAnrVVrnFbWnbWBk91U2","witnesses":[{"invocation":"DEDblVguNGXWbUswDvBfVJzBt76BJyJ0Ga6siquyjioGn4Dbr6zy1IvcLl3xN5akcejRy9e+Mr1qvpe/gkLgtW4QDEDRwPISZagMFjE/plXTnZ/gEU0IbBAAe23U29zVWteUmzRsPxF/MdzXvdffR9W0edkj17AmkWpn+5rqzH9aCOpLDECEvjgxZaRoAHEDNzp1REllLcGzMwrwSjudtzfgRglQL3g1BKerDx6cGHH73medRVkL9QVm4KzSxlywVtvhwBMrDEBuPKvzg5TtakFW2jr/bfmy1bn2FiLARlOySwaGdKRV93ozA5lVEIAvHbBlJtT4/5H8jHjbncXXMrP3OUHqebZz","verification":"EwwhAhA6f33QFlWFl/eWDSfFFqQ5T9loueZRVetLAT5AQEBuDCECp7xV/oaE4BGXaNEEujB5W9zIZhnoZK3SYVZyPtGFzWIMIQKzYiv0AXvf4xfFiu1fTHU/IGt9uJYEb6fXdLvEv3+NwgwhA9kMB99j5pDOd5EuEKtRrMlEtmhgI3tgjE+PgwnnHuaZFAtBMHOzuw=="}],"consensusdata":{"primary":0,"nonce":"0000000000000457"},"tx":[{"hash":"0xf97a72b7722c109f909a8bc16c22368c5023d85828b09b127b237aace33cf099","size":265,"version":0,"nonce":9,"sender":"NQRLhCpAru9BjGsMwk67vdMwmzKMRgsnnN","sysfee":"0","netfee":"365210","validuntilblock":1200,"attributes":[],"cosigners":[{"account":"0x870958fd19ee3f6c7dc3c2df399d013910856e31","scopes":"CalledByEntry"}],"script":"AHsMFCBygnSvr8NvQ6Bx0yjPo+Yp2cuwDBQxboUQOQGdOd/Cw31sP+4Z/VgJhxPADAh0cmFuc2ZlcgwU2gHvYphOfQUnXEpYeyAtoLP3X+ZBYn1bUjg=","witnesses":[{"invocation":"DECwklSj3liZOJbktRtkVdUCu8U2LQlrU6Dv8NtMgd0xXbk5lXjc2p68xv6xtJXbJ4aoFMJZ9lkcNpGoeUCcaCet","verification":"DCECs2Ir9AF73+MXxYrtX0x1PyBrfbiWBG+n13S7xL9/jcILQQqQatQ="}]}]}]}`,
`{"jsonrpc":"2.0","method":"block_added","params":[{"size":1641,"nextblockhash":"0x003abea54aa3c5edba7e33fb7ca96452cb65ff8cd36ce1cdfd412a6c4d3ea38a","confirmations":6,"hash":"0xd9518e322440714b0564d6f84a9a39b527b5480e4e7f7932895777a4c8fa0a9e","version":0,"previousblockhash":"0xa496577895eb8c227bb866dc44f99f21c0cf06417ca8f2a877cc5d761a50dac0","merkleroot":"0x2b0f84636d814f3a952de145c8f4028f5664132f2719f5902e1884c9fba59806","time":1596101407001,"index":1,"nextconsensus":"NUVPACMnKFhpuHjsRjhUvXz1XhqfGZYVtY","witnesses":[{"invocation":"DEANAGtuw7+VLVNvmpESGL4+xqlKgBSIWmMBEtABi86ixft2Q7AcaOC89M+yKVIuTel9doVJcCvfx93CcQ63DZqCDEBtwUEkjuzP9h8ZTL0GEKfGr01pazmh8s2TswJge5sAGryYE/+kjw5NCLFmowhPU73qUYQ9jq1zMNMXF+Deqxp/DEDkytkkwJec5n4x2+l5zsZHT6QTXJsByZOWXaGPVJKK8CeDccZba7Mf4MdSkWqSt61xUtlgM2Iqhe/Iuokf/ZEXDEAOH72S12CuAxVu0XNGyj3cgMtad+Bghxvr16T9+ELaWkpR4ko26FdStYC2XiCkzanXTtAD1Id5rREsxfFeKb83","verification":"EwwhAhA6f33QFlWFl/eWDSfFFqQ5T9loueZRVetLAT5AQEBuDCECp7xV/oaE4BGXaNEEujB5W9zIZhnoZK3SYVZyPtGFzWIMIQKzYiv0AXvf4xfFiu1fTHU/IGt9uJYEb6fXdLvEv3+NwgwhA9kMB99j5pDOd5EuEKtRrMlEtmhgI3tgjE+PgwnnHuaZFAtBE43vrw=="}],"consensusdata":{"primary":0,"nonce":"0000000000000457"},"tx":[{"hash":"0x32f9bd3a2707475407c41bf5daacf9560e25ed74f6d85b3afb2ef72edb2325ba","size":555,"version":0,"nonce":2,"sender":"NUVPACMnKFhpuHjsRjhUvXz1XhqfGZYVtY","sysfee":"10000000","netfee":"4488350","validuntilblock":1200,"attributes":[],"signers":[{"account":"0x95307cb9cc8c4578cef9f6845895eb7aa8be125e","scopes":"CalledByEntry"}],"script":"Ahjd9QUMFKqKz4WdT+QCs05nPyFWgheWpIjrDBReEr6oeuuVWIT2+c54RYzMuXwwlRPADAh0cmFuc2ZlcgwUJQWey0h406h1+RxRzt7TMNRXX95BYn1bUjg=","witnesses":[{"invocation":"DEAIcSUsAtRql4t+IEeo+p4+YI7bA6PG+1xxUkPIb2vNlaMl4PumjQVFT+bg2ldxCYa6zccoc4n0Gfryi82EhGpGDECR4fQDr4njo94mF6/GA+OH0Y5k735yGMEZHs96586BRp6f0AQxfmIPvLcS4Yero9p0zgVl9BDg3TxU5piRylR5DEAcjOT7JjEwNRnKgDDkXfh63Yc3MorMbdb2asTiDu0aexy5M5XcikA1jypJT4wkhxjp0rrgFZRSzeYhwV0Klz+yDECIopKxLd4p+hLHxFq07WffXd++sN0WIRWzvMJncCrJqSP8zz65r8TGFFzvZMdGelWKO7KhBOhIK6wryuWNlaDI","verification":"EwwhAhA6f33QFlWFl/eWDSfFFqQ5T9loueZRVetLAT5AQEBuDCECp7xV/oaE4BGXaNEEujB5W9zIZhnoZK3SYVZyPtGFzWIMIQKzYiv0AXvf4xfFiu1fTHU/IGt9uJYEb6fXdLvEv3+NwgwhA9kMB99j5pDOd5EuEKtRrMlEtmhgI3tgjE+PgwnnHuaZFAtBE43vrw=="}]},{"hash":"0xd35d6386ec2f29b90839536f6af9466098d1665e951cdd0a20db6b4629b08369","size":559,"version":0,"nonce":3,"sender":"NUVPACMnKFhpuHjsRjhUvXz1XhqfGZYVtY","sysfee":"10000000","netfee":"4492350","validuntilblock":1200,"attributes":[],"signers":[{"account":"0x95307cb9cc8c4578cef9f6845895eb7aa8be125e","scopes":"CalledByEntry"}],"script":"AwDodkgXAAAADBSqis+FnU/kArNOZz8hVoIXlqSI6wwUXhK+qHrrlViE9vnOeEWMzLl8MJUTwAwIdHJhbnNmZXIMFLyvQdaEx9StbuDZnalwe50fDI5mQWJ9W1I4","witnesses":[{"invocation":"DECKUPl9d502XPI564EC2BroqpN274uV3n1z6kCBCmbS715lzmPbh24LESMsAP2TFohhdhm16aDfNsPi5tkB/FE4DEDzJFts9VYc1lIivGAZZSxACzAV/96Kn2WAaS3bDIlAJHCShsfz+Rn3NuvMyutujYM4vyEipAX9gkjcvFWGKRObDECkI883onhG9aYTxwQWDxsmofuiooRJOic/cJ1H8nqUEvMqATYKgdHaBOJBVYsKq9M9oUv/fj6JFbMDrcasvpiaDECEqkq2b50aEc1NGM9DBAsYLEeZHrM1BwX3a2tBOeeD/KLtmTga1IZogsZgpis2BOToZO6LuN9FJYcn+/iGcC5u","verification":"EwwhAhA6f33QFlWFl/eWDSfFFqQ5T9loueZRVetLAT5AQEBuDCECp7xV/oaE4BGXaNEEujB5W9zIZhnoZK3SYVZyPtGFzWIMIQKzYiv0AXvf4xfFiu1fTHU/IGt9uJYEb6fXdLvEv3+NwgwhA9kMB99j5pDOd5EuEKtRrMlEtmhgI3tgjE+PgwnnHuaZFAtBE43vrw=="}]}]}]}`,
`{"jsonrpc":"2.0","method":"event_missed","params":[]}`,
}
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
@ -204,13 +204,13 @@ func TestWSFilteredSubscriptions(t *testing.T) {
filt, ok := param.Value.(request.TxFilter)
require.Equal(t, true, ok)
require.Equal(t, util.Uint160{1, 2, 3, 4, 5}, *filt.Sender)
require.Nil(t, filt.Cosigner)
require.Nil(t, filt.Signer)
},
},
{"transactions cosigner",
{"transactions signer",
func(t *testing.T, wsc *WSClient) {
cosigner := util.Uint160{0, 42}
_, err := wsc.SubscribeForNewTransactions(nil, &cosigner)
signer := util.Uint160{0, 42}
_, err := wsc.SubscribeForNewTransactions(nil, &signer)
require.NoError(t, err)
},
func(t *testing.T, p *request.Params) {
@ -220,14 +220,14 @@ func TestWSFilteredSubscriptions(t *testing.T) {
filt, ok := param.Value.(request.TxFilter)
require.Equal(t, true, ok)
require.Nil(t, filt.Sender)
require.Equal(t, util.Uint160{0, 42}, *filt.Cosigner)
require.Equal(t, util.Uint160{0, 42}, *filt.Signer)
},
},
{"transactions sender and cosigner",
{"transactions sender and signer",
func(t *testing.T, wsc *WSClient) {
sender := util.Uint160{1, 2, 3, 4, 5}
cosigner := util.Uint160{0, 42}
_, err := wsc.SubscribeForNewTransactions(&sender, &cosigner)
signer := util.Uint160{0, 42}
_, err := wsc.SubscribeForNewTransactions(&sender, &signer)
require.NoError(t, err)
},
func(t *testing.T, p *request.Params) {
@ -237,7 +237,7 @@ func TestWSFilteredSubscriptions(t *testing.T) {
filt, ok := param.Value.(request.TxFilter)
require.Equal(t, true, ok)
require.Equal(t, util.Uint160{1, 2, 3, 4, 5}, *filt.Sender)
require.Equal(t, util.Uint160{0, 42}, *filt.Cosigner)
require.Equal(t, util.Uint160{0, 42}, *filt.Signer)
},
},
{"notifications",

View file

@ -37,10 +37,10 @@ type (
Primary int `json:"primary"`
}
// TxFilter is a wrapper structure for transaction event filter. It
// allows to filter transactions by senders and cosigners.
// allows to filter transactions by senders and signers.
TxFilter struct {
Sender *util.Uint160 `json:"sender,omitempty"`
Cosigner *util.Uint160 `json:"cosigner,omitempty"`
Signer *util.Uint160 `json:"signer,omitempty"`
}
// NotificationFilter is a wrapper structure representing filter used for
// notifications generated during transaction execution. Notifications can
@ -67,7 +67,7 @@ const (
TxFilterT
NotificationFilterT
ExecutionFilterT
Cosigner
Signer
)
var errMissingParameter = errors.New("parameter is missing")
@ -207,24 +207,24 @@ func (p *Param) GetBytesBase64() ([]byte, error) {
return base64.StdEncoding.DecodeString(s)
}
// GetCosigner returns transaction.Cosigner value of the parameter.
func (p Param) GetCosigner() (transaction.Cosigner, error) {
c, ok := p.Value.(transaction.Cosigner)
// GetSigner returns transaction.Signer value of the parameter.
func (p Param) GetSigner() (transaction.Signer, error) {
c, ok := p.Value.(transaction.Signer)
if !ok {
return transaction.Cosigner{}, errors.New("not a cosigner")
return transaction.Signer{}, errors.New("not a signer")
}
return c, nil
}
// GetCosigners returns a slice of transaction.Cosigner with global scope from
// array of Uint160 or array of serialized transaction.Cosigner stored in the
// GetSigners returns a slice of transaction.Signer with global scope from
// array of Uint160 or array of serialized transaction.Signer stored in the
// parameter.
func (p Param) GetCosigners() ([]transaction.Cosigner, error) {
func (p Param) GetSigners() ([]transaction.Signer, error) {
hashes, err := p.GetArray()
if err != nil {
return nil, err
}
cosigners := make([]transaction.Cosigner, len(hashes))
signers := make([]transaction.Signer, len(hashes))
// try to extract hashes first
for i, h := range hashes {
var u util.Uint160
@ -232,20 +232,20 @@ func (p Param) GetCosigners() ([]transaction.Cosigner, error) {
if err != nil {
break
}
cosigners[i] = transaction.Cosigner{
signers[i] = transaction.Signer{
Account: u,
Scopes: transaction.Global,
}
}
if err != nil {
for i, h := range hashes {
cosigners[i], err = h.GetCosigner()
signers[i], err = h.GetSigner()
if err != nil {
return nil, err
}
}
}
return cosigners, nil
return signers, nil
}
// UnmarshalJSON implements json.Unmarshaler interface.
@ -261,7 +261,7 @@ func (p *Param) UnmarshalJSON(data []byte) error {
{TxFilterT, &TxFilter{}},
{NotificationFilterT, &NotificationFilter{}},
{ExecutionFilterT, &ExecutionFilter{}},
{Cosigner, &transaction.Cosigner{}},
{Signer, &transaction.Signer{}},
{ArrayT, &[]Param{}},
}
@ -296,7 +296,7 @@ func (p *Param) UnmarshalJSON(data []byte) error {
} else {
continue
}
case *transaction.Cosigner:
case *transaction.Signer:
p.Value = *val
case *[]Param:
p.Value = *val

View file

@ -18,8 +18,8 @@ func TestParam_UnmarshalJSON(t *testing.T) {
msg := `["str1", 123, null, ["str2", 3], [{"type": "String", "value": "jajaja"}],
{"primary": 1},
{"sender": "f84d6a337fbc3d3a201d41da99e86b479e7a2554"},
{"cosigner": "f84d6a337fbc3d3a201d41da99e86b479e7a2554"},
{"sender": "f84d6a337fbc3d3a201d41da99e86b479e7a2554", "cosigner": "f84d6a337fbc3d3a201d41da99e86b479e7a2554"},
{"signer": "f84d6a337fbc3d3a201d41da99e86b479e7a2554"},
{"sender": "f84d6a337fbc3d3a201d41da99e86b479e7a2554", "signer": "f84d6a337fbc3d3a201d41da99e86b479e7a2554"},
{"contract": "f84d6a337fbc3d3a201d41da99e86b479e7a2554"},
{"state": "HALT"},
{"account": "0xcadb3dc2faa3ef14a13b619c9a43124755aa2569"},
@ -78,11 +78,11 @@ func TestParam_UnmarshalJSON(t *testing.T) {
},
{
Type: TxFilterT,
Value: TxFilter{Cosigner: &contr},
Value: TxFilter{Signer: &contr},
},
{
Type: TxFilterT,
Value: TxFilter{Sender: &contr, Cosigner: &contr},
Value: TxFilter{Sender: &contr, Signer: &contr},
},
{
Type: NotificationFilterT,
@ -93,8 +93,8 @@ func TestParam_UnmarshalJSON(t *testing.T) {
Value: ExecutionFilter{State: "HALT"},
},
{
Type: Cosigner,
Value: transaction.Cosigner{
Type: Signer,
Value: transaction.Signer{
Account: accountHash,
Scopes: transaction.FeeOnly,
},
@ -103,8 +103,8 @@ func TestParam_UnmarshalJSON(t *testing.T) {
Type: ArrayT,
Value: []Param{
{
Type: Cosigner,
Value: transaction.Cosigner{
Type: Signer,
Value: transaction.Signer{
Account: accountHash,
Scopes: transaction.Global,
},
@ -280,22 +280,22 @@ func TestParamGetBytesBase64(t *testing.T) {
require.NotNil(t, err)
}
func TestParamGetCosigner(t *testing.T) {
c := transaction.Cosigner{
func TestParamGetSigner(t *testing.T) {
c := transaction.Signer{
Account: util.Uint160{1, 2, 3, 4},
Scopes: transaction.Global,
}
p := Param{Type: Cosigner, Value: c}
actual, err := p.GetCosigner()
p := Param{Type: Signer, Value: c}
actual, err := p.GetSigner()
require.NoError(t, err)
require.Equal(t, c, actual)
p = Param{Type: Cosigner, Value: `{"account": "0xcadb3dc2faa3ef14a13b619c9a43124755aa2569", "scopes": 0}`}
_, err = p.GetCosigner()
p = Param{Type: Signer, Value: `{"account": "0xcadb3dc2faa3ef14a13b619c9a43124755aa2569", "scopes": 0}`}
_, err = p.GetSigner()
require.Error(t, err)
}
func TestParamGetCosigners(t *testing.T) {
func TestParamGetSigners(t *testing.T) {
u1 := util.Uint160{1, 2, 3, 4}
u2 := util.Uint160{5, 6, 7, 8}
t.Run("from hashes", func(t *testing.T) {
@ -303,19 +303,19 @@ func TestParamGetCosigners(t *testing.T) {
{Type: StringT, Value: u1.StringLE()},
{Type: StringT, Value: u2.StringLE()},
}}
actual, err := p.GetCosigners()
actual, err := p.GetSigners()
require.NoError(t, err)
require.Equal(t, 2, len(actual))
require.True(t, u1.Equals(actual[0].Account))
require.True(t, u2.Equals(actual[1].Account))
})
t.Run("from cosigners", func(t *testing.T) {
c1 := transaction.Cosigner{
t.Run("from signers", func(t *testing.T) {
c1 := transaction.Signer{
Account: u1,
Scopes: transaction.Global,
}
c2 := transaction.Cosigner{
c2 := transaction.Signer{
Account: u2,
Scopes: transaction.CustomContracts,
AllowedContracts: []util.Uint160{
@ -324,10 +324,10 @@ func TestParamGetCosigners(t *testing.T) {
},
}
p := Param{ArrayT, []Param{
{Type: Cosigner, Value: c1},
{Type: Cosigner, Value: c2},
{Type: Signer, Value: c1},
{Type: Signer, Value: c2},
}}
actual, err := p.GetCosigners()
actual, err := p.GetSigners()
require.NoError(t, err)
require.Equal(t, 2, len(actual))
require.Equal(t, c1, actual[0])
@ -339,7 +339,7 @@ func TestParamGetCosigners(t *testing.T) {
{Type: StringT, Value: u1.StringLE()},
{Type: StringT, Value: "bla"},
}}
_, err := p.GetCosigners()
_, err := p.GetSigners()
require.Error(t, err)
})
}

View file

@ -843,13 +843,16 @@ func (s *Server) invokeFunction(reqParams request.Params) (interface{}, *respons
tx := &transaction.Transaction{}
checkWitnessHashesIndex := len(reqParams)
if checkWitnessHashesIndex > 3 {
cosigners, err := reqParams[3].GetCosigners()
signers, err := reqParams[3].GetSigners()
if err != nil {
return nil, response.ErrInvalidParams
}
tx.Cosigners = cosigners
tx.Signers = signers
checkWitnessHashesIndex--
}
if len(tx.Signers) == 0 {
tx.Signers = []transaction.Signer{{Account: util.Uint160{}, Scopes: transaction.FeeOnly}}
}
script, err := request.CreateFunctionInvocationScript(scriptHash, reqParams[1:checkWitnessHashesIndex])
if err != nil {
return nil, response.NewInternalServerError("can't create invocation script", err)
@ -871,11 +874,14 @@ func (s *Server) invokescript(reqParams request.Params) (interface{}, *response.
tx := &transaction.Transaction{}
if len(reqParams) > 1 {
cosigners, err := reqParams[1].GetCosigners()
signers, err := reqParams[1].GetSigners()
if err != nil {
return nil, response.ErrInvalidParams
}
tx.Cosigners = cosigners
tx.Signers = signers
}
if len(tx.Signers) == 0 {
tx.Signers = []transaction.Signer{{Account: util.Uint160{}, Scopes: transaction.FeeOnly}}
}
tx.Script = script
return s.runScriptInVM(script, tx), nil

View file

@ -52,7 +52,7 @@ type rpcTestCase struct {
}
const testContractHash = "36c3b0c85d98607db00b711885ec3e411d9b1672"
const deploymentTxHash = "ef4209bc06e1d8412995c645a8497d3e2c9a05ca52236de94297c6db9c3e94d0"
const deploymentTxHash = "60a1fc8ceb7948d9933aec0cedd148441568575c40af7e0985cc366ed153d57e"
var rpcTestCases = map[string][]rpcTestCase{
"getapplicationlog": {
@ -589,12 +589,12 @@ var rpcTestCases = map[string][]rpcTestCase{
"sendrawtransaction": {
{
name: "positive",
params: `["000a000000aa8acf859d4fe402b34e673f2156821796a488eb80969800000000009269130000000000b00400000001aa8acf859d4fe402b34e673f2156821796a488eb015d0300e87648170000000c1478ba4c24009fe510e136c9995a2e05215e1be4dc0c14aa8acf859d4fe402b34e673f2156821796a488eb13c00c087472616e736665720c14897720d8cd76f4f00abfa37c0edd889c208fde9b41627d5b523801420c4040719393aa590d962cb5a48e16360ac75a6c358c9699e9f1a853afede4d601b6783e28f5ec74542aaf59519e76830ba9d267656db324461fdb08d1d51521e103290c2102b3622bf4017bdfe317c58aed5f4c753f206b7db896046fa7d774bbc4bf7f8dc20b4195440d78"]`,
params: `["000a0000008096980000000000721b130000000000b004000001aa8acf859d4fe402b34e673f2156821796a488eb01005d0300e87648170000000c1478ba4c24009fe510e136c9995a2e05215e1be4dc0c14aa8acf859d4fe402b34e673f2156821796a488eb13c00c087472616e736665720c1425059ecb4878d3a875f91c51ceded330d4575fde41627d5b523801420c40b99503c74bb1861b0b45060501dd090224f6c404aca8c02ccba3243c9b9691c1ef9e6b824d731f8fab27c56ba75609d32d2d176e97f56d9e3780610c83ebd41a290c2102b3622bf4017bdfe317c58aed5f4c753f206b7db896046fa7d774bbc4bf7f8dc20b4195440d78"]`,
result: func(e *executor) interface{} { return &result.RelayResult{} },
check: func(t *testing.T, e *executor, inv interface{}) {
res, ok := inv.(*result.RelayResult)
require.True(t, ok)
expectedHash, err := util.Uint256DecodeStringLE("72159b0cf1221110daad6e1df6ef4ff03012173b63c86910bd7134deb659c875")
expectedHash, err := util.Uint256DecodeStringLE("8b6e610a2205914411b26c4380594fa9a1e16961ff5896ed3b16831a151c6dd0")
require.NoError(t, err)
assert.Equal(t, expectedHash, res.Hash)
},
@ -744,7 +744,7 @@ func testRPCProtocol(t *testing.T, doRPCCall func(string, string, *testing.T) []
tx := transaction.New(testchain.Network(), []byte{byte(opcode.PUSH1)}, 0)
tx.Nonce = height + 1
tx.ValidUntilBlock = height + 10
tx.Sender = acc0.PrivateKey().GetScriptHash()
tx.Signers = []transaction.Signer{{Account: acc0.PrivateKey().GetScriptHash()}}
addNetworkFee(tx)
require.NoError(t, acc0.SignTx(tx))
return tx
@ -872,6 +872,7 @@ func testRPCProtocol(t *testing.T, doRPCCall func(string, string, *testing.T) []
}
for i := 0; i < 5; i++ {
tx := transaction.New(testchain.Network(), []byte{byte(opcode.PUSH1)}, 0)
tx.Signers = []transaction.Signer{{Account: util.Uint160{1, 2, 3}}}
assert.NoError(t, mp.Add(tx, &FeerStub{}))
expected = append(expected, tx.Hash())
}
@ -1000,7 +1001,7 @@ func checkNep5Balances(t *testing.T, e *executor, acc interface{}) {
},
{
Asset: e.chain.UtilityTokenHash(),
Amount: "915.79002700",
Amount: "915.78962700",
LastUpdated: 6,
}},
Address: testchain.PrivateKeyByID(0).GetScriptHash().StringLE(),
@ -1101,7 +1102,7 @@ func checkNep5Transfers(t *testing.T, e *executor, acc interface{}) {
b, err := e.chain.GetBlock(h)
require.NoError(t, err)
for j := range b.Transactions {
if u.Equals(b.Transactions[j].Sender) {
if u.Equals(b.Transactions[j].Sender()) {
amount := b.Transactions[j].SystemFee + b.Transactions[j].NetworkFee
expected.Sent = append(expected.Sent, result.NEP5Transfer{
Timestamp: b.Timestamp,

View file

@ -58,18 +58,18 @@ func (f *feed) Matches(r *response.Notification) bool {
case response.TransactionEventID:
filt := f.filter.(request.TxFilter)
tx := r.Payload[0].(*transaction.Transaction)
senderOK := filt.Sender == nil || tx.Sender.Equals(*filt.Sender)
cosignerOK := true
if filt.Cosigner != nil {
cosignerOK = false
for i := range tx.Cosigners {
if tx.Cosigners[i].Account.Equals(*filt.Cosigner) {
cosignerOK = true
senderOK := filt.Sender == nil || tx.Sender().Equals(*filt.Sender)
signerOK := true
if filt.Signer != nil {
signerOK = false
for i := range tx.Signers {
if tx.Signers[i].Account.Equals(*filt.Signer) {
signerOK = true
break
}
}
}
return senderOK && cosignerOK
return senderOK && signerOK
case response.NotificationEventID:
filt := f.filter.(request.NotificationFilter)
notification := r.Payload[0].(result.NotificationEvent)

View file

@ -147,28 +147,28 @@ func TestFilteredSubscriptions(t *testing.T) {
require.Equal(t, address.Uint160ToString(goodSender), sender)
},
},
"tx matching cosigner": {
params: `["transaction_added", {"cosigner":"` + goodSender.StringLE() + `"}]`,
"tx matching signer": {
params: `["transaction_added", {"signer":"` + goodSender.StringLE() + `"}]`,
check: func(t *testing.T, resp *response.Notification) {
rmap := resp.Payload[0].(map[string]interface{})
require.Equal(t, response.TransactionEventID, resp.Event)
cosigners := rmap["cosigners"].([]interface{})
cosigner0 := cosigners[0].(map[string]interface{})
cosigner0acc := cosigner0["account"].(string)
require.Equal(t, "0x"+goodSender.StringLE(), cosigner0acc)
signers := rmap["signers"].([]interface{})
signer0 := signers[0].(map[string]interface{})
signer0acc := signer0["account"].(string)
require.Equal(t, "0x"+goodSender.StringLE(), signer0acc)
},
},
"tx matching sender and cosigner": {
params: `["transaction_added", {"sender":"` + goodSender.StringLE() + `", "cosigner":"` + goodSender.StringLE() + `"}]`,
"tx matching sender and signer": {
params: `["transaction_added", {"sender":"` + goodSender.StringLE() + `", "signer":"` + goodSender.StringLE() + `"}]`,
check: func(t *testing.T, resp *response.Notification) {
rmap := resp.Payload[0].(map[string]interface{})
require.Equal(t, response.TransactionEventID, resp.Event)
sender := rmap["sender"].(string)
require.Equal(t, address.Uint160ToString(goodSender), sender)
cosigners := rmap["cosigners"].([]interface{})
cosigner0 := cosigners[0].(map[string]interface{})
cosigner0acc := cosigner0["account"].(string)
require.Equal(t, "0x"+goodSender.StringLE(), cosigner0acc)
signers := rmap["signers"].([]interface{})
signer0 := signers[0].(map[string]interface{})
signer0acc := signer0["account"].(string)
require.Equal(t, "0x"+goodSender.StringLE(), signer0acc)
},
},
"notification matching": {

Binary file not shown.

View file

@ -169,6 +169,7 @@ func getContractTx() *transaction.Transaction {
tx := transaction.New(netmode.UnitTestNet, []byte{byte(opcode.PUSH1)}, 0)
tx.Attributes = make([]transaction.Attribute, 0)
tx.Scripts = make([]transaction.Witness, 0)
tx.Signers = []transaction.Signer{{Account: util.Uint160{1, 2, 3}}}
tx.Hash()
return tx
}