forked from TrueCloudLab/neoneo-go
Merge pull request #1244 from nspcc-dev/transaction/signers
core: move transaction sender to signers
This commit is contained in:
commit
058a26b647
37 changed files with 360 additions and 300 deletions
|
@ -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,12 @@ 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,
|
||||
}
|
||||
)
|
||||
data := strings.SplitN(c, ":", 2)
|
||||
s := data[0]
|
||||
|
@ -704,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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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))),
|
||||
|
|
|
@ -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())
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
package transaction
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"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"
|
||||
|
@ -9,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"`
|
||||
|
@ -18,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 {
|
||||
|
@ -30,9 +32,17 @@ 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|FeeOnly) != 0 {
|
||||
br.Err = errors.New("unknown witness scope")
|
||||
return
|
||||
}
|
||||
if c.Scopes&Global != 0 && c.Scopes != Global {
|
||||
br.Err = errors.New("global scope can not be combined with other scopes")
|
||||
return
|
||||
}
|
||||
if c.Scopes&CustomContracts != 0 {
|
||||
br.ReadArray(&c.AllowedContracts, maxSubitems)
|
||||
}
|
|
@ -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)
|
||||
}
|
|
@ -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,
|
||||
}
|
||||
|
@ -126,44 +123,15 @@ func (t *Transaction) VerificationHash() util.Uint256 {
|
|||
// transaction, which are all fields except the scripts.
|
||||
func (t *Transaction) decodeHashableFields(br *io.BinReader) {
|
||||
t.Version = uint8(br.ReadB())
|
||||
if t.Version > 0 {
|
||||
br.Err = errors.New("only version 0 is supported")
|
||||
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")
|
||||
return
|
||||
}
|
||||
t.NetworkFee = int64(br.ReadU64LE())
|
||||
if t.NetworkFee < 0 {
|
||||
br.Err = errors.New("negative network fee")
|
||||
return
|
||||
}
|
||||
if t.NetworkFee+t.SystemFee < t.SystemFee {
|
||||
br.Err = errors.New("too big fees: int 64 overflow")
|
||||
return
|
||||
}
|
||||
t.ValidUntilBlock = br.ReadU32LE()
|
||||
|
||||
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.Signers, MaxAttributes)
|
||||
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")
|
||||
return
|
||||
if br.Err == nil {
|
||||
br.Err = t.isValid()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -197,17 +165,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)
|
||||
}
|
||||
|
||||
|
@ -293,6 +255,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 {
|
||||
|
@ -305,7 +276,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"`
|
||||
}
|
||||
|
@ -317,10 +288,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,
|
||||
|
@ -339,19 +310,47 @@ 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")
|
||||
}
|
||||
|
||||
return t.isValid()
|
||||
}
|
||||
|
||||
// isValid checks whether decoded/unmarshalled transaction has all fields valid.
|
||||
func (t *Transaction) isValid() error {
|
||||
if t.Version > 0 {
|
||||
return errors.New("only version 0 is supported")
|
||||
}
|
||||
if t.SystemFee < 0 {
|
||||
return errors.New("negative system fee")
|
||||
}
|
||||
if t.NetworkFee < 0 {
|
||||
return errors.New("negative network fee")
|
||||
}
|
||||
if t.NetworkFee+t.SystemFee < t.SystemFee {
|
||||
return errors.New("too big fees: int64 overflow")
|
||||
}
|
||||
if len(t.Signers) == 0 {
|
||||
return errors.New("signers array should contain sender")
|
||||
}
|
||||
for i := 0; i < len(t.Signers); i++ {
|
||||
if i > 0 && t.Signers[i].Scopes == FeeOnly {
|
||||
return errors.New("FeeOnly scope can be used only for sender")
|
||||
}
|
||||
for j := i + 1; j < len(t.Signers); j++ {
|
||||
if t.Signers[i].Account.Equals(t.Signers[j].Account) {
|
||||
return errors.New("transaction signers should be unique")
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(t.Script) == 0 {
|
||||
return errors.New("no script")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -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{},
|
||||
|
|
|
@ -7,13 +7,12 @@ import (
|
|||
"strings"
|
||||
)
|
||||
|
||||
// WitnessScope represents set of witness flags for Transaction cosigner.
|
||||
// WitnessScope represents set of witness flags for Transaction signer.
|
||||
type WitnessScope byte
|
||||
|
||||
const (
|
||||
// Global allows this witness in all contexts (default Neo2 behavior).
|
||||
// This cannot be combined with other flags.
|
||||
Global WitnessScope = 0x00
|
||||
// FeeOnly is only valid for a sender, it can't be used during the execution.
|
||||
FeeOnly WitnessScope = 0
|
||||
// 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
|
||||
|
@ -23,6 +22,9 @@ const (
|
|||
CustomContracts WitnessScope = 0x10
|
||||
// CustomGroups define custom pubkey for group members.
|
||||
CustomGroups WitnessScope = 0x20
|
||||
// Global allows this witness in all contexts (default Neo2 behavior).
|
||||
// This cannot be combined with other flags.
|
||||
Global WitnessScope = 0x80
|
||||
)
|
||||
|
||||
// ScopesFromString converts string of comma-separated scopes to a set of scopes
|
||||
|
@ -40,6 +42,7 @@ func ScopesFromString(s string) (WitnessScope, error) {
|
|||
CalledByEntry.String(): CalledByEntry,
|
||||
CustomContracts.String(): CustomContracts,
|
||||
CustomGroups.String(): CustomGroups,
|
||||
FeeOnly.String(): FeeOnly,
|
||||
}
|
||||
var isGlobal bool
|
||||
for _, scopeStr := range scopes {
|
||||
|
@ -61,8 +64,8 @@ func ScopesFromString(s string) (WitnessScope, error) {
|
|||
// scopesToString converts witness scope to it's string representation. It uses
|
||||
// `, ` to separate scope names.
|
||||
func scopesToString(scopes WitnessScope) string {
|
||||
if scopes == Global {
|
||||
return "Global"
|
||||
if scopes&Global != 0 || scopes == FeeOnly {
|
||||
return scopes.String()
|
||||
}
|
||||
var res string
|
||||
if scopes&CalledByEntry != 0 {
|
||||
|
|
|
@ -8,20 +8,22 @@ func _() {
|
|||
// An "invalid array index" compiler error signifies that the constant values have changed.
|
||||
// Re-run the stringer command to generate them again.
|
||||
var x [1]struct{}
|
||||
_ = x[Global-0]
|
||||
_ = x[FeeOnly-0]
|
||||
_ = x[CalledByEntry-1]
|
||||
_ = x[CustomContracts-16]
|
||||
_ = x[CustomGroups-32]
|
||||
_ = x[Global-128]
|
||||
}
|
||||
|
||||
const (
|
||||
_WitnessScope_name_0 = "GlobalCalledByEntry"
|
||||
_WitnessScope_name_0 = "FeeOnlyCalledByEntry"
|
||||
_WitnessScope_name_1 = "CustomContracts"
|
||||
_WitnessScope_name_2 = "CustomGroups"
|
||||
_WitnessScope_name_3 = "Global"
|
||||
)
|
||||
|
||||
var (
|
||||
_WitnessScope_index_0 = [...]uint8{0, 6, 19}
|
||||
_WitnessScope_index_0 = [...]uint8{0, 7, 20}
|
||||
)
|
||||
|
||||
func (i WitnessScope) String() string {
|
||||
|
@ -32,6 +34,8 @@ func (i WitnessScope) String() string {
|
|||
return _WitnessScope_name_1
|
||||
case i == 32:
|
||||
return _WitnessScope_name_2
|
||||
case i == 128:
|
||||
return _WitnessScope_name_3
|
||||
default:
|
||||
return "WitnessScope(" + strconv.FormatInt(int64(i), 10) + ")"
|
||||
}
|
||||
|
|
|
@ -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{},
|
||||
|
|
|
@ -17,11 +17,7 @@ func TestGenesisBlockMainNet(t *testing.T) {
|
|||
block, err := createGenesisBlock(cfg.ProtocolConfiguration)
|
||||
require.NoError(t, err)
|
||||
|
||||
//TODO: After we added Nonce field to transaction.Transaction, goveringTockenTx and UtilityTockenTx hashes
|
||||
// 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())
|
||||
}
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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},
|
||||
}})
|
||||
},
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,18 +93,18 @@ func TestParam_UnmarshalJSON(t *testing.T) {
|
|||
Value: ExecutionFilter{State: "HALT"},
|
||||
},
|
||||
{
|
||||
Type: Cosigner,
|
||||
Value: transaction.Cosigner{
|
||||
Type: Signer,
|
||||
Value: transaction.Signer{
|
||||
Account: accountHash,
|
||||
Scopes: transaction.Global,
|
||||
Scopes: transaction.FeeOnly,
|
||||
},
|
||||
},
|
||||
{
|
||||
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)
|
||||
})
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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": {
|
||||
|
|
BIN
pkg/rpc/server/testdata/testblocks.acc
vendored
BIN
pkg/rpc/server/testdata/testblocks.acc
vendored
Binary file not shown.
|
@ -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
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue