2020-02-17 12:17:02 +00:00
|
|
|
package server
|
2019-01-22 12:14:52 +00:00
|
|
|
|
|
|
|
import (
|
|
|
|
"bytes"
|
2020-11-06 14:37:58 +00:00
|
|
|
"encoding/base64"
|
2019-09-18 15:21:16 +00:00
|
|
|
"encoding/json"
|
2019-01-22 12:14:52 +00:00
|
|
|
"fmt"
|
|
|
|
"io/ioutil"
|
2020-07-09 09:57:24 +00:00
|
|
|
"math/big"
|
2019-01-22 12:14:52 +00:00
|
|
|
"net/http"
|
|
|
|
"net/http/httptest"
|
2019-11-21 16:41:28 +00:00
|
|
|
"reflect"
|
2020-09-21 12:34:04 +00:00
|
|
|
"sort"
|
2020-08-07 06:42:44 +00:00
|
|
|
"strconv"
|
2019-02-09 15:53:58 +00:00
|
|
|
"strings"
|
2019-01-22 12:14:52 +00:00
|
|
|
"testing"
|
2020-04-23 13:32:53 +00:00
|
|
|
"time"
|
2019-01-22 12:14:52 +00:00
|
|
|
|
2020-04-29 12:25:58 +00:00
|
|
|
"github.com/gorilla/websocket"
|
2020-11-23 11:09:00 +00:00
|
|
|
"github.com/nspcc-dev/neo-go/internal/testchain"
|
|
|
|
"github.com/nspcc-dev/neo-go/internal/testserdes"
|
2021-02-09 09:05:45 +00:00
|
|
|
"github.com/nspcc-dev/neo-go/pkg/config/netmode"
|
2020-03-03 14:21:42 +00:00
|
|
|
"github.com/nspcc-dev/neo-go/pkg/core"
|
2020-04-23 13:02:01 +00:00
|
|
|
"github.com/nspcc-dev/neo-go/pkg/core/block"
|
2020-09-28 14:56:16 +00:00
|
|
|
"github.com/nspcc-dev/neo-go/pkg/core/fee"
|
2020-06-09 09:12:56 +00:00
|
|
|
"github.com/nspcc-dev/neo-go/pkg/core/state"
|
2020-03-03 14:21:42 +00:00
|
|
|
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
|
2020-09-28 11:58:04 +00:00
|
|
|
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
2020-03-05 12:16:03 +00:00
|
|
|
"github.com/nspcc-dev/neo-go/pkg/encoding/address"
|
2020-03-04 17:35:37 +00:00
|
|
|
"github.com/nspcc-dev/neo-go/pkg/io"
|
2021-02-09 09:05:45 +00:00
|
|
|
"github.com/nspcc-dev/neo-go/pkg/network/payload"
|
2020-03-03 14:21:42 +00:00
|
|
|
"github.com/nspcc-dev/neo-go/pkg/rpc/response"
|
|
|
|
"github.com/nspcc-dev/neo-go/pkg/rpc/response/result"
|
2021-02-03 19:01:20 +00:00
|
|
|
rpc2 "github.com/nspcc-dev/neo-go/pkg/services/oracle/broadcaster"
|
2020-09-03 16:58:50 +00:00
|
|
|
"github.com/nspcc-dev/neo-go/pkg/smartcontract/trigger"
|
2020-03-03 14:21:42 +00:00
|
|
|
"github.com/nspcc-dev/neo-go/pkg/util"
|
2020-09-03 16:58:50 +00:00
|
|
|
"github.com/nspcc-dev/neo-go/pkg/vm"
|
2020-06-05 09:17:16 +00:00
|
|
|
"github.com/nspcc-dev/neo-go/pkg/vm/opcode"
|
2020-04-23 13:32:53 +00:00
|
|
|
"github.com/nspcc-dev/neo-go/pkg/wallet"
|
2019-01-22 12:14:52 +00:00
|
|
|
"github.com/stretchr/testify/assert"
|
2019-11-21 16:41:28 +00:00
|
|
|
"github.com/stretchr/testify/require"
|
2019-01-22 12:14:52 +00:00
|
|
|
)
|
|
|
|
|
2019-11-21 16:41:28 +00:00
|
|
|
type executor struct {
|
|
|
|
chain *core.Blockchain
|
2020-04-29 12:14:56 +00:00
|
|
|
httpSrv *httptest.Server
|
2019-11-21 16:41:28 +00:00
|
|
|
}
|
2019-02-20 17:39:32 +00:00
|
|
|
|
2019-11-21 16:41:28 +00:00
|
|
|
const (
|
|
|
|
defaultJSONRPC = "2.0"
|
|
|
|
defaultID = 1
|
|
|
|
)
|
2019-02-20 17:39:32 +00:00
|
|
|
|
2019-11-21 16:41:28 +00:00
|
|
|
type rpcTestCase struct {
|
|
|
|
name string
|
|
|
|
params string
|
|
|
|
fail bool
|
|
|
|
result func(e *executor) interface{}
|
|
|
|
check func(t *testing.T, e *executor, result interface{})
|
|
|
|
}
|
Implement rpc server method: sendrawtransaction (#174)
* Added new config attributes: 'SecondsPerBlock','LowPriorityThreshold'
* Added new files:
* Added new method: CompareTo
* Fixed empty Slice case
* Added new methods: LessThan, GreaterThan, Equal, CompareTo
* Added new method: InputIntersection
* Added MaxTransactionSize, GroupOutputByAssetID
* Added ned method: ScriptHash
* Added new method: IsDoubleSpend
* Refactor blockchainer, Added Feer interface, Verify and GetMemPool method
* 1) Added MemPool
2) Added new methods to satisfy the blockchainer interface: IsLowPriority, Verify, GetMemPool
* Added new methods: RelayTxn, RelayDirectly
* Fixed tests
* Implemented RPC server method sendrawtransaction
* Refactor getrawtransaction, sendrawtransaction in separate methods
* Moved 'secondsPerBlock' to config file
* Implemented Kim suggestions:
1) Fixed data race issues
2) refactor Verify method
3) Get rid of unused InputIntersection method due to refactoring Verify method
4) Fixed bug in https://github.com/CityOfZion/neo-go/pull/174#discussion_r264108135
5) minor simplications of the code
* Fixed minor issues related to
1) space
2) getter methods do not need pointer on the receiver
3) error message
4) refactoring CompareTo method in uint256.go
* Fixed small issues
* Use sync.RWMutex instead of sync.Mutex
* Refined (R)Lock/(R)Unlock
* return error instead of bool in Verify methods
2019-03-20 12:30:05 +00:00
|
|
|
|
2021-01-22 09:22:48 +00:00
|
|
|
const testContractHash = "c6436aab21ebd15279b85af8d7b5808d38455b0a"
|
2021-02-09 09:05:45 +00:00
|
|
|
const deploymentTxHash = "d0de42d5d23211174a50d74fbd4a919631236a63f16431a5a7e7126759e7ba23"
|
2020-12-08 15:28:00 +00:00
|
|
|
const genesisBlockHash = "0542f4350c6e236d0509bcd98188b0034bfbecc1a0c7fcdb8e4295310d468b70"
|
2020-08-24 11:00:05 +00:00
|
|
|
|
2021-01-22 09:22:48 +00:00
|
|
|
const verifyContractHash = "03ffc0897543b9b709e0f8cab4a7682dae0ba943"
|
2020-09-30 10:50:58 +00:00
|
|
|
const verifyContractAVM = "570300412d51083021700c14aa8acf859d4fe402b34e673f2156821796a488ebdb30716813cedb2869db289740"
|
2020-10-14 13:46:06 +00:00
|
|
|
const testVerifyContractAVM = "VwcADBQBDAMOBQYMDQIODw0DDgcJAAAAANswcGgRVUH4J+yMIaonBwAAABFADBQNDwMCCQACAQMHAwQFAgEADgYMCdswcWkRVUH4J+yMIaonBwAAABJAE0A="
|
2020-03-05 15:26:54 +00:00
|
|
|
|
2019-11-21 16:41:28 +00:00
|
|
|
var rpcTestCases = map[string][]rpcTestCase{
|
2020-02-21 14:56:28 +00:00
|
|
|
"getapplicationlog": {
|
|
|
|
{
|
|
|
|
name: "positive",
|
2020-06-18 09:00:51 +00:00
|
|
|
params: `["` + deploymentTxHash + `"]`,
|
2020-11-11 15:43:28 +00:00
|
|
|
result: func(e *executor) interface{} { return &result.ApplicationLog{} },
|
2020-02-21 14:56:28 +00:00
|
|
|
check: func(t *testing.T, e *executor, acc interface{}) {
|
2020-11-11 15:43:28 +00:00
|
|
|
res, ok := acc.(*result.ApplicationLog)
|
2020-02-21 14:56:28 +00:00
|
|
|
require.True(t, ok)
|
2020-06-18 09:00:51 +00:00
|
|
|
expectedTxHash, err := util.Uint256DecodeStringLE(deploymentTxHash)
|
2020-03-04 14:45:29 +00:00
|
|
|
require.NoError(t, err)
|
2020-11-11 15:43:28 +00:00
|
|
|
assert.Equal(t, 1, len(res.Executions))
|
|
|
|
assert.Equal(t, expectedTxHash, res.Container)
|
|
|
|
assert.Equal(t, trigger.Application, res.Executions[0].Trigger)
|
|
|
|
assert.Equal(t, vm.HaltState, res.Executions[0].VMState)
|
2020-02-21 14:56:28 +00:00
|
|
|
},
|
|
|
|
},
|
2020-11-10 11:30:00 +00:00
|
|
|
{
|
|
|
|
name: "positive, genesis block",
|
|
|
|
params: `["` + genesisBlockHash + `"]`,
|
|
|
|
result: func(e *executor) interface{} { return &result.ApplicationLog{} },
|
|
|
|
check: func(t *testing.T, e *executor, acc interface{}) {
|
|
|
|
res, ok := acc.(*result.ApplicationLog)
|
|
|
|
require.True(t, ok)
|
|
|
|
assert.Equal(t, genesisBlockHash, res.Container.StringLE())
|
2020-12-08 15:28:00 +00:00
|
|
|
assert.Equal(t, 2, len(res.Executions))
|
|
|
|
assert.Equal(t, trigger.OnPersist, res.Executions[0].Trigger)
|
|
|
|
assert.Equal(t, trigger.PostPersist, res.Executions[1].Trigger)
|
2020-11-10 11:30:00 +00:00
|
|
|
assert.Equal(t, vm.HaltState, res.Executions[0].VMState)
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "positive, genesis block, postPersist",
|
|
|
|
params: `["` + genesisBlockHash + `", "PostPersist"]`,
|
|
|
|
result: func(e *executor) interface{} { return &result.ApplicationLog{} },
|
|
|
|
check: func(t *testing.T, e *executor, acc interface{}) {
|
|
|
|
res, ok := acc.(*result.ApplicationLog)
|
|
|
|
require.True(t, ok)
|
|
|
|
assert.Equal(t, genesisBlockHash, res.Container.StringLE())
|
|
|
|
assert.Equal(t, 1, len(res.Executions))
|
2020-12-08 15:28:00 +00:00
|
|
|
assert.Equal(t, trigger.PostPersist, res.Executions[0].Trigger)
|
2020-11-10 11:30:00 +00:00
|
|
|
assert.Equal(t, vm.HaltState, res.Executions[0].VMState)
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "positive, genesis block, onPersist",
|
|
|
|
params: `["` + genesisBlockHash + `", "OnPersist"]`,
|
|
|
|
result: func(e *executor) interface{} { return &result.ApplicationLog{} },
|
|
|
|
check: func(t *testing.T, e *executor, acc interface{}) {
|
|
|
|
res, ok := acc.(*result.ApplicationLog)
|
|
|
|
require.True(t, ok)
|
|
|
|
assert.Equal(t, genesisBlockHash, res.Container.StringLE())
|
2020-12-08 15:28:00 +00:00
|
|
|
assert.Equal(t, 1, len(res.Executions))
|
|
|
|
assert.Equal(t, trigger.OnPersist, res.Executions[0].Trigger)
|
|
|
|
assert.Equal(t, vm.HaltState, res.Executions[0].VMState)
|
2020-02-21 14:56:28 +00:00
|
|
|
},
|
|
|
|
},
|
rpc: fix `getapplicationlog` RPC handler
Fixes the following panic:
```
2020/12/22 18:16:09 http: panic serving 127.0.0.1:50228: runtime error: invalid memory address or nil pointer dereference
goroutine 4043 [running]:
net/http.(*conn).serve.func1(0xc00094c960)
net/http/server.go:1772 +0x139
panic(0xcd9b40, 0x16a94e0)
runtime/panic.go:973 +0x396
github.com/nspcc-dev/neo-go/pkg/rpc/server.(*Server).getApplicationLog(0xc000094ea0, 0xc000472d20, 0x2, 0x4, 0xc0000be228, 0xc0007ad601, 0x28)
github.com/nspcc-dev/neo-go/pkg/rpc/server/server.go:542 +0xac
github.com/nspcc-dev/neo-go/pkg/rpc/server.(*Server).handleIn(0xc000094ea0, 0xc000089770, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, ...)
github.com/nspcc-dev/neo-go/pkg/rpc/server/server.go:326 +0x981
github.com/nspcc-dev/neo-go/pkg/rpc/server.(*Server).handleRequest(0xc000094ea0, 0xc001bccba0, 0x0, 0x0, 0x0)
github.com/nspcc-dev/neo-go/pkg/rpc/server/server.go:296 +0x26a
github.com/nspcc-dev/neo-go/pkg/rpc/server.(*Server).handleHTTPRequest(0xc000094ea0, 0x1071f40, 0xc000b089a0, 0xc00053c200)
github.com/nspcc-dev/neo-go/pkg/rpc/server/server.go:290 +0x91b
net/http.HandlerFunc.ServeHTTP(0xc0004e61b0, 0x1071f40, 0xc000b089a0, 0xc00053c200)
net/http/server.go:2012 +0x44
net/http.serverHandler.ServeHTTP(0xc0000d2ee0, 0x1071f40, 0xc000b089a0, 0xc00053c200)
net/http/server.go:2807 +0xa3
net/http.(*conn).serve(0xc00094c960, 0x10749c0, 0xc0006ae980)
net/http/server.go:1895 +0x86c
created by net/http.(*Server).Serve
net/http/server.go:2933 +0x35c
```
2020-12-22 15:21:04 +00:00
|
|
|
{
|
|
|
|
name: "invalid trigger (not a string)",
|
|
|
|
params: `["` + genesisBlockHash + `", 1]`,
|
|
|
|
fail: true,
|
|
|
|
},
|
2020-02-21 14:56:28 +00:00
|
|
|
{
|
|
|
|
name: "no params",
|
|
|
|
params: `[]`,
|
|
|
|
fail: true,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "invalid address",
|
|
|
|
params: `["notahash"]`,
|
|
|
|
fail: true,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "invalid tx hash",
|
|
|
|
params: `["d24cc1d52b5c0216cbf3835bb5bac8ccf32639fa1ab6627ec4e2b9f33f7ec02f"]`,
|
|
|
|
fail: true,
|
|
|
|
},
|
|
|
|
},
|
2020-02-15 17:00:38 +00:00
|
|
|
"getcontractstate": {
|
|
|
|
{
|
2020-09-25 09:40:57 +00:00
|
|
|
name: "positive, by hash",
|
2020-03-05 15:26:54 +00:00
|
|
|
params: fmt.Sprintf(`["%s"]`, testContractHash),
|
2020-06-09 09:12:56 +00:00
|
|
|
result: func(e *executor) interface{} { return &state.Contract{} },
|
2020-02-21 12:10:59 +00:00
|
|
|
check: func(t *testing.T, e *executor, cs interface{}) {
|
2020-06-09 09:12:56 +00:00
|
|
|
res, ok := cs.(*state.Contract)
|
2020-02-15 17:00:38 +00:00
|
|
|
require.True(t, ok)
|
2020-11-18 20:10:48 +00:00
|
|
|
assert.Equal(t, testContractHash, res.Hash.StringLE())
|
2020-02-15 17:00:38 +00:00
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
2020-09-25 09:40:57 +00:00
|
|
|
name: "positive, by id",
|
2021-01-15 21:17:31 +00:00
|
|
|
params: `[1]`,
|
2020-09-25 09:40:57 +00:00
|
|
|
result: func(e *executor) interface{} { return &state.Contract{} },
|
|
|
|
check: func(t *testing.T, e *executor, cs interface{}) {
|
|
|
|
res, ok := cs.(*state.Contract)
|
|
|
|
require.True(t, ok)
|
2021-01-15 21:17:31 +00:00
|
|
|
assert.Equal(t, int32(1), res.ID)
|
2020-09-25 09:40:57 +00:00
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "positive, native by id",
|
|
|
|
params: `[-3]`,
|
|
|
|
result: func(e *executor) interface{} { return &state.Contract{} },
|
|
|
|
check: func(t *testing.T, e *executor, cs interface{}) {
|
|
|
|
res, ok := cs.(*state.Contract)
|
|
|
|
require.True(t, ok)
|
|
|
|
assert.Equal(t, int32(-3), res.ID)
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "positive, native by name",
|
2020-12-13 18:25:04 +00:00
|
|
|
params: `["PolicyContract"]`,
|
2020-09-25 09:40:57 +00:00
|
|
|
result: func(e *executor) interface{} { return &state.Contract{} },
|
|
|
|
check: func(t *testing.T, e *executor, cs interface{}) {
|
|
|
|
res, ok := cs.(*state.Contract)
|
|
|
|
require.True(t, ok)
|
2021-02-03 19:01:20 +00:00
|
|
|
assert.Equal(t, int32(-5), res.ID)
|
2020-09-25 09:40:57 +00:00
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "negative, bad hash",
|
2020-02-15 17:00:38 +00:00
|
|
|
params: `["6d1eeca891ee93de2b7a77eb91c26f3b3c04d6c3"]`,
|
|
|
|
fail: true,
|
|
|
|
},
|
2020-09-25 09:40:57 +00:00
|
|
|
{
|
|
|
|
name: "negative, bad ID",
|
2021-02-03 19:01:20 +00:00
|
|
|
params: `[-100]`,
|
2020-09-25 09:40:57 +00:00
|
|
|
fail: true,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "negative, bad native name",
|
|
|
|
params: `["unknown_native"]`,
|
|
|
|
fail: true,
|
|
|
|
},
|
2020-02-15 17:00:38 +00:00
|
|
|
{
|
|
|
|
name: "no params",
|
|
|
|
params: `[]`,
|
|
|
|
fail: true,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "invalid hash",
|
|
|
|
params: `["notahex"]`,
|
|
|
|
fail: true,
|
|
|
|
},
|
|
|
|
},
|
2020-03-05 11:50:06 +00:00
|
|
|
|
2020-11-24 08:14:25 +00:00
|
|
|
"getnep17balances": {
|
2020-03-05 11:50:06 +00:00
|
|
|
{
|
|
|
|
name: "no params",
|
|
|
|
params: `[]`,
|
|
|
|
fail: true,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "invalid address",
|
|
|
|
params: `["notahex"]`,
|
|
|
|
fail: true,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "positive",
|
2020-04-22 10:15:31 +00:00
|
|
|
params: `["` + testchain.PrivateKeyByID(0).GetScriptHash().StringLE() + `"]`,
|
2020-11-24 08:14:25 +00:00
|
|
|
result: func(e *executor) interface{} { return &result.NEP17Balances{} },
|
|
|
|
check: checkNep17Balances,
|
2020-07-03 15:10:07 +00:00
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "positive_address",
|
|
|
|
params: `["` + address.Uint160ToString(testchain.PrivateKeyByID(0).GetScriptHash()) + `"]`,
|
2020-11-24 08:14:25 +00:00
|
|
|
result: func(e *executor) interface{} { return &result.NEP17Balances{} },
|
|
|
|
check: checkNep17Balances,
|
2020-03-05 11:50:06 +00:00
|
|
|
},
|
|
|
|
},
|
2020-11-24 08:14:25 +00:00
|
|
|
"getnep17transfers": {
|
2020-03-05 12:16:03 +00:00
|
|
|
{
|
|
|
|
name: "no params",
|
|
|
|
params: `[]`,
|
|
|
|
fail: true,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "invalid address",
|
|
|
|
params: `["notahex"]`,
|
|
|
|
fail: true,
|
|
|
|
},
|
2020-08-07 06:42:44 +00:00
|
|
|
{
|
|
|
|
name: "invalid timestamp",
|
|
|
|
params: `["` + testchain.PrivateKeyByID(0).Address() + `", "notanumber"]`,
|
|
|
|
fail: true,
|
|
|
|
},
|
2020-09-12 21:12:45 +00:00
|
|
|
{
|
|
|
|
name: "invalid stop timestamp",
|
|
|
|
params: `["` + testchain.PrivateKeyByID(0).Address() + `", "1", "blah"]`,
|
|
|
|
fail: true,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "invalid limit",
|
|
|
|
params: `["` + testchain.PrivateKeyByID(0).Address() + `", "1", "2", "0"]`,
|
|
|
|
fail: true,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "invalid limit 2",
|
|
|
|
params: `["` + testchain.PrivateKeyByID(0).Address() + `", "1", "2", "bleh"]`,
|
|
|
|
fail: true,
|
|
|
|
},
|
2020-09-14 14:48:17 +00:00
|
|
|
{
|
|
|
|
name: "invalid limit 3",
|
|
|
|
params: `["` + testchain.PrivateKeyByID(0).Address() + `", "1", "2", "100500"]`,
|
|
|
|
fail: true,
|
|
|
|
},
|
2020-09-12 21:12:45 +00:00
|
|
|
{
|
|
|
|
name: "invalid page",
|
|
|
|
params: `["` + testchain.PrivateKeyByID(0).Address() + `", "1", "2", "3", "-1"]`,
|
|
|
|
fail: true,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "invalid page 2",
|
|
|
|
params: `["` + testchain.PrivateKeyByID(0).Address() + `", "1", "2", "3", "jajaja"]`,
|
|
|
|
fail: true,
|
|
|
|
},
|
2020-03-05 12:16:03 +00:00
|
|
|
{
|
|
|
|
name: "positive",
|
2020-08-07 06:42:44 +00:00
|
|
|
params: `["` + testchain.PrivateKeyByID(0).Address() + `", 0]`,
|
2020-11-24 08:14:25 +00:00
|
|
|
result: func(e *executor) interface{} { return &result.NEP17Transfers{} },
|
|
|
|
check: checkNep17Transfers,
|
2020-07-03 15:25:18 +00:00
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "positive_hash",
|
2020-08-07 06:42:44 +00:00
|
|
|
params: `["` + testchain.PrivateKeyByID(0).GetScriptHash().StringLE() + `", 0]`,
|
2020-11-24 08:14:25 +00:00
|
|
|
result: func(e *executor) interface{} { return &result.NEP17Transfers{} },
|
|
|
|
check: checkNep17Transfers,
|
2020-03-05 12:16:03 +00:00
|
|
|
},
|
|
|
|
},
|
2020-06-04 08:59:22 +00:00
|
|
|
"getproof": {
|
|
|
|
{
|
|
|
|
name: "no params",
|
|
|
|
params: `[]`,
|
|
|
|
fail: true,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "invalid root",
|
|
|
|
params: `["0xabcdef"]`,
|
|
|
|
fail: true,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "invalid contract",
|
|
|
|
params: `["0000000000000000000000000000000000000000000000000000000000000000", "0xabcdef"]`,
|
|
|
|
fail: true,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "invalid key",
|
|
|
|
params: `["0000000000000000000000000000000000000000000000000000000000000000", "` + testContractHash + `", "notahex"]`,
|
|
|
|
fail: true,
|
|
|
|
},
|
|
|
|
},
|
2020-06-04 08:09:07 +00:00
|
|
|
"getstateheight": {
|
|
|
|
{
|
|
|
|
name: "positive",
|
|
|
|
params: `[]`,
|
|
|
|
result: func(_ *executor) interface{} { return new(result.StateHeight) },
|
|
|
|
check: func(t *testing.T, e *executor, res interface{}) {
|
|
|
|
sh, ok := res.(*result.StateHeight)
|
|
|
|
require.True(t, ok)
|
|
|
|
|
|
|
|
require.Equal(t, e.chain.BlockHeight(), sh.BlockHeight)
|
|
|
|
require.Equal(t, uint32(0), sh.StateHeight)
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
2020-06-03 15:09:36 +00:00
|
|
|
"getstateroot": {
|
|
|
|
{
|
|
|
|
name: "no params",
|
|
|
|
params: `[]`,
|
|
|
|
fail: true,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "invalid hash",
|
|
|
|
params: `["0x1234567890"]`,
|
|
|
|
fail: true,
|
|
|
|
},
|
|
|
|
},
|
2020-01-30 08:03:44 +00:00
|
|
|
"getstorage": {
|
|
|
|
{
|
|
|
|
name: "positive",
|
2021-02-07 15:27:19 +00:00
|
|
|
params: fmt.Sprintf(`["%s", "dGVzdGtleQ=="]`, testContractHash),
|
2020-02-21 12:10:59 +00:00
|
|
|
result: func(e *executor) interface{} {
|
2021-02-07 15:27:19 +00:00
|
|
|
v := base64.StdEncoding.EncodeToString([]byte("testvalue"))
|
2020-02-21 12:10:59 +00:00
|
|
|
return &v
|
2020-01-30 08:03:44 +00:00
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "missing key",
|
2021-02-07 15:27:19 +00:00
|
|
|
params: fmt.Sprintf(`["%s", "dGU="]`, testContractHash),
|
2020-02-21 12:10:59 +00:00
|
|
|
result: func(e *executor) interface{} {
|
|
|
|
v := ""
|
|
|
|
return &v
|
2020-01-30 08:03:44 +00:00
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "no params",
|
|
|
|
params: `[]`,
|
|
|
|
fail: true,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "no second parameter",
|
2020-03-05 15:26:54 +00:00
|
|
|
params: fmt.Sprintf(`["%s"]`, testContractHash),
|
2020-01-30 08:03:44 +00:00
|
|
|
fail: true,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "invalid hash",
|
|
|
|
params: `["notahex"]`,
|
|
|
|
fail: true,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "invalid key",
|
2021-02-07 15:27:19 +00:00
|
|
|
params: fmt.Sprintf(`["%s", "notabase64$"]`, testContractHash),
|
2020-01-30 08:03:44 +00:00
|
|
|
fail: true,
|
|
|
|
},
|
|
|
|
},
|
2019-11-21 16:41:28 +00:00
|
|
|
"getbestblockhash": {
|
|
|
|
{
|
|
|
|
params: "[]",
|
|
|
|
result: func(e *executor) interface{} {
|
2020-02-21 12:10:59 +00:00
|
|
|
v := "0x" + e.chain.CurrentBlockHash().StringLE()
|
|
|
|
return &v
|
2019-11-21 16:41:28 +00:00
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
params: "1",
|
|
|
|
fail: true,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
"getblock": {
|
|
|
|
{
|
|
|
|
name: "positive",
|
2020-05-08 17:54:24 +00:00
|
|
|
params: "[3, 1]",
|
2020-06-18 09:00:51 +00:00
|
|
|
result: func(_ *executor) interface{} { return &result.Block{} },
|
2020-02-21 12:10:59 +00:00
|
|
|
check: func(t *testing.T, e *executor, blockRes interface{}) {
|
|
|
|
res, ok := blockRes.(*result.Block)
|
2019-11-21 16:41:28 +00:00
|
|
|
require.True(t, ok)
|
Implement rpc server method: sendrawtransaction (#174)
* Added new config attributes: 'SecondsPerBlock','LowPriorityThreshold'
* Added new files:
* Added new method: CompareTo
* Fixed empty Slice case
* Added new methods: LessThan, GreaterThan, Equal, CompareTo
* Added new method: InputIntersection
* Added MaxTransactionSize, GroupOutputByAssetID
* Added ned method: ScriptHash
* Added new method: IsDoubleSpend
* Refactor blockchainer, Added Feer interface, Verify and GetMemPool method
* 1) Added MemPool
2) Added new methods to satisfy the blockchainer interface: IsLowPriority, Verify, GetMemPool
* Added new methods: RelayTxn, RelayDirectly
* Fixed tests
* Implemented RPC server method sendrawtransaction
* Refactor getrawtransaction, sendrawtransaction in separate methods
* Moved 'secondsPerBlock' to config file
* Implemented Kim suggestions:
1) Fixed data race issues
2) refactor Verify method
3) Get rid of unused InputIntersection method due to refactoring Verify method
4) Fixed bug in https://github.com/CityOfZion/neo-go/pull/174#discussion_r264108135
5) minor simplications of the code
* Fixed minor issues related to
1) space
2) getter methods do not need pointer on the receiver
3) error message
4) refactoring CompareTo method in uint256.go
* Fixed small issues
* Use sync.RWMutex instead of sync.Mutex
* Refined (R)Lock/(R)Unlock
* return error instead of bool in Verify methods
2019-03-20 12:30:05 +00:00
|
|
|
|
2020-05-08 17:54:24 +00:00
|
|
|
block, err := e.chain.GetBlock(e.chain.GetHeaderHash(3))
|
2019-11-21 16:41:28 +00:00
|
|
|
require.NoErrorf(t, err, "could not get block")
|
Implement rpc server method: sendrawtransaction (#174)
* Added new config attributes: 'SecondsPerBlock','LowPriorityThreshold'
* Added new files:
* Added new method: CompareTo
* Fixed empty Slice case
* Added new methods: LessThan, GreaterThan, Equal, CompareTo
* Added new method: InputIntersection
* Added MaxTransactionSize, GroupOutputByAssetID
* Added ned method: ScriptHash
* Added new method: IsDoubleSpend
* Refactor blockchainer, Added Feer interface, Verify and GetMemPool method
* 1) Added MemPool
2) Added new methods to satisfy the blockchainer interface: IsLowPriority, Verify, GetMemPool
* Added new methods: RelayTxn, RelayDirectly
* Fixed tests
* Implemented RPC server method sendrawtransaction
* Refactor getrawtransaction, sendrawtransaction in separate methods
* Moved 'secondsPerBlock' to config file
* Implemented Kim suggestions:
1) Fixed data race issues
2) refactor Verify method
3) Get rid of unused InputIntersection method due to refactoring Verify method
4) Fixed bug in https://github.com/CityOfZion/neo-go/pull/174#discussion_r264108135
5) minor simplications of the code
* Fixed minor issues related to
1) space
2) getter methods do not need pointer on the receiver
3) error message
4) refactoring CompareTo method in uint256.go
* Fixed small issues
* Use sync.RWMutex instead of sync.Mutex
* Refined (R)Lock/(R)Unlock
* return error instead of bool in Verify methods
2019-03-20 12:30:05 +00:00
|
|
|
|
2020-05-13 18:27:08 +00:00
|
|
|
assert.Equal(t, block.Hash(), res.Hash())
|
|
|
|
for i, tx := range res.Transactions {
|
2020-04-22 17:42:38 +00:00
|
|
|
actualTx := block.Transactions[i]
|
2020-02-12 14:25:44 +00:00
|
|
|
require.True(t, ok)
|
2020-05-08 17:54:24 +00:00
|
|
|
require.Equal(t, actualTx.Nonce, tx.Nonce)
|
|
|
|
require.Equal(t, block.Transactions[i].Hash(), tx.Hash())
|
2020-02-12 14:25:44 +00:00
|
|
|
}
|
2019-11-21 16:41:28 +00:00
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "no params",
|
|
|
|
params: `[]`,
|
|
|
|
fail: true,
|
|
|
|
},
|
2019-11-26 10:31:11 +00:00
|
|
|
{
|
|
|
|
name: "bad params",
|
|
|
|
params: `[[]]`,
|
|
|
|
fail: true,
|
|
|
|
},
|
2019-11-21 16:41:28 +00:00
|
|
|
{
|
|
|
|
name: "invalid height",
|
|
|
|
params: `[-1]`,
|
|
|
|
fail: true,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "invalid hash",
|
|
|
|
params: `["notahex"]`,
|
|
|
|
fail: true,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "missing hash",
|
|
|
|
params: `["` + util.Uint256{}.String() + `"]`,
|
|
|
|
fail: true,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
"getblockcount": {
|
|
|
|
{
|
|
|
|
params: "[]",
|
2020-02-21 12:10:59 +00:00
|
|
|
result: func(e *executor) interface{} {
|
|
|
|
v := int(e.chain.BlockHeight() + 1)
|
|
|
|
return &v
|
|
|
|
},
|
2019-11-21 16:41:28 +00:00
|
|
|
},
|
|
|
|
},
|
|
|
|
"getblockhash": {
|
|
|
|
{
|
|
|
|
params: "[1]",
|
2020-02-21 12:10:59 +00:00
|
|
|
result: func(e *executor) interface{} {
|
|
|
|
// We don't have `t` here for proper handling, but
|
|
|
|
// error here would lead to panic down below.
|
|
|
|
block, _ := e.chain.GetBlock(e.chain.GetHeaderHash(1))
|
2019-11-27 09:23:18 +00:00
|
|
|
expectedHash := "0x" + block.Hash().StringLE()
|
2020-02-21 12:10:59 +00:00
|
|
|
return &expectedHash
|
2019-11-21 16:41:28 +00:00
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "string height",
|
|
|
|
params: `["first"]`,
|
|
|
|
fail: true,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "invalid number height",
|
|
|
|
params: `[-2]`,
|
|
|
|
fail: true,
|
|
|
|
},
|
|
|
|
},
|
2020-03-04 17:35:37 +00:00
|
|
|
"getblockheader": {
|
|
|
|
{
|
|
|
|
name: "invalid verbose type",
|
2020-04-20 17:38:47 +00:00
|
|
|
params: `["9673799c5b5a294427401cb07d6cc615ada3a0d5c5bf7ed6f0f54f24abb2e2ac", true]`,
|
2020-03-04 17:35:37 +00:00
|
|
|
fail: true,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "invalid block hash",
|
|
|
|
params: `["notahash"]`,
|
|
|
|
fail: true,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "unknown block",
|
|
|
|
params: `["a6e526375a780335112299f2262501e5e9574c3ba61b16bbc1e282b344f6c141"]`,
|
|
|
|
fail: true,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "no params",
|
|
|
|
params: `[]`,
|
|
|
|
fail: true,
|
|
|
|
},
|
|
|
|
},
|
2021-02-07 19:01:22 +00:00
|
|
|
"getblockheadercount": {
|
|
|
|
{
|
|
|
|
params: "[]",
|
|
|
|
result: func(e *executor) interface{} {
|
|
|
|
v := int(e.chain.HeaderHeight() + 1)
|
|
|
|
return &v
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
2020-02-19 09:44:31 +00:00
|
|
|
"getblocksysfee": {
|
|
|
|
{
|
|
|
|
name: "positive",
|
|
|
|
params: "[1]",
|
|
|
|
result: func(e *executor) interface{} {
|
|
|
|
block, _ := e.chain.GetBlock(e.chain.GetHeaderHash(1))
|
|
|
|
|
2020-06-23 14:15:35 +00:00
|
|
|
var expectedBlockSysFee int64
|
2020-02-19 09:44:31 +00:00
|
|
|
for _, tx := range block.Transactions {
|
2020-05-08 17:54:24 +00:00
|
|
|
expectedBlockSysFee += tx.SystemFee
|
2020-02-19 09:44:31 +00:00
|
|
|
}
|
|
|
|
return &expectedBlockSysFee
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "no params",
|
|
|
|
params: `[]`,
|
|
|
|
fail: true,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "string height",
|
|
|
|
params: `["first"]`,
|
|
|
|
fail: true,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "invalid number height",
|
|
|
|
params: `[-2]`,
|
|
|
|
fail: true,
|
2020-09-21 12:34:04 +00:00
|
|
|
},
|
|
|
|
},
|
|
|
|
"getcommittee": {
|
|
|
|
{
|
|
|
|
params: "[]",
|
|
|
|
result: func(e *executor) interface{} {
|
|
|
|
// it's a test chain, so committee is a sorted standby committee
|
|
|
|
expected := e.chain.GetStandByCommittee()
|
|
|
|
sort.Sort(expected)
|
|
|
|
return &expected
|
|
|
|
},
|
2020-02-19 09:44:31 +00:00
|
|
|
},
|
|
|
|
},
|
2019-11-21 16:41:28 +00:00
|
|
|
"getconnectioncount": {
|
|
|
|
{
|
|
|
|
params: "[]",
|
2020-02-21 12:10:59 +00:00
|
|
|
result: func(*executor) interface{} {
|
|
|
|
v := 0
|
|
|
|
return &v
|
|
|
|
},
|
2019-11-21 16:41:28 +00:00
|
|
|
},
|
|
|
|
},
|
2021-02-09 09:25:38 +00:00
|
|
|
"getnativecontracts": {
|
|
|
|
{
|
|
|
|
params: "[]",
|
|
|
|
result: func(e *executor) interface{} {
|
|
|
|
return new([]state.NativeContract)
|
|
|
|
},
|
|
|
|
check: func(t *testing.T, e *executor, res interface{}) {
|
|
|
|
lst := res.(*[]state.NativeContract)
|
|
|
|
for i := range *lst {
|
|
|
|
cs := e.chain.GetContractState((*lst)[i].Hash)
|
|
|
|
require.NotNil(t, cs)
|
|
|
|
require.True(t, cs.ID <= 0)
|
|
|
|
}
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
2019-11-21 16:41:28 +00:00
|
|
|
"getpeers": {
|
|
|
|
{
|
|
|
|
params: "[]",
|
|
|
|
result: func(*executor) interface{} {
|
2020-02-21 12:10:59 +00:00
|
|
|
return &result.GetPeers{
|
|
|
|
Unconnected: []result.Peer{},
|
|
|
|
Connected: []result.Peer{},
|
|
|
|
Bad: []result.Peer{},
|
2019-11-21 16:41:28 +00:00
|
|
|
}
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
"getrawtransaction": {
|
|
|
|
{
|
|
|
|
name: "no params",
|
|
|
|
params: `[]`,
|
|
|
|
fail: true,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "invalid hash",
|
|
|
|
params: `["notahex"]`,
|
|
|
|
fail: true,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "missing hash",
|
|
|
|
params: `["` + util.Uint256{}.String() + `"]`,
|
|
|
|
fail: true,
|
|
|
|
},
|
|
|
|
},
|
2020-03-05 14:20:50 +00:00
|
|
|
"gettransactionheight": {
|
|
|
|
{
|
2020-04-16 14:10:42 +00:00
|
|
|
name: "positive",
|
2020-06-18 09:00:51 +00:00
|
|
|
params: `["` + deploymentTxHash + `"]`,
|
2020-03-05 14:20:50 +00:00
|
|
|
result: func(e *executor) interface{} {
|
2020-06-04 19:21:12 +00:00
|
|
|
h := 0
|
2020-03-05 14:20:50 +00:00
|
|
|
return &h
|
|
|
|
},
|
2020-06-04 19:21:12 +00:00
|
|
|
check: func(t *testing.T, e *executor, resp interface{}) {
|
|
|
|
h, ok := resp.(*int)
|
|
|
|
require.True(t, ok)
|
|
|
|
assert.Equal(t, 2, *h)
|
|
|
|
},
|
2020-03-05 14:20:50 +00:00
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "no params",
|
|
|
|
params: `[]`,
|
|
|
|
fail: true,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "invalid hash",
|
|
|
|
params: `["notahex"]`,
|
|
|
|
fail: true,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "missing hash",
|
|
|
|
params: `["` + util.Uint256{}.String() + `"]`,
|
|
|
|
fail: true,
|
|
|
|
},
|
|
|
|
},
|
2020-06-01 20:27:03 +00:00
|
|
|
"getunclaimedgas": {
|
2020-03-06 17:38:17 +00:00
|
|
|
{
|
|
|
|
name: "no params",
|
|
|
|
params: "[]",
|
|
|
|
fail: true,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "invalid address",
|
|
|
|
params: `["invalid"]`,
|
|
|
|
fail: true,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "positive",
|
2020-04-22 10:15:31 +00:00
|
|
|
params: `["` + testchain.MultisigAddress() + `"]`,
|
2020-03-06 17:38:17 +00:00
|
|
|
result: func(*executor) interface{} {
|
2020-07-09 14:25:26 +00:00
|
|
|
return &result.UnclaimedGas{}
|
2020-03-06 17:38:17 +00:00
|
|
|
},
|
2020-06-01 20:27:03 +00:00
|
|
|
check: func(t *testing.T, e *executor, resp interface{}) {
|
2020-07-09 14:25:26 +00:00
|
|
|
actual, ok := resp.(*result.UnclaimedGas)
|
2020-03-06 17:38:17 +00:00
|
|
|
require.True(t, ok)
|
2020-07-09 14:25:26 +00:00
|
|
|
expected := result.UnclaimedGas{
|
|
|
|
Address: testchain.MultisigScriptHash(),
|
2021-02-09 09:05:45 +00:00
|
|
|
Unclaimed: *big.NewInt(4500),
|
2020-07-09 14:25:26 +00:00
|
|
|
}
|
|
|
|
assert.Equal(t, expected, *actual)
|
2020-03-06 17:38:17 +00:00
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
2020-10-01 12:26:54 +00:00
|
|
|
"getnextblockvalidators": {
|
2020-03-05 14:48:30 +00:00
|
|
|
{
|
|
|
|
params: "[]",
|
|
|
|
result: func(*executor) interface{} {
|
|
|
|
return &[]result.Validator{}
|
|
|
|
},
|
2020-08-10 14:51:46 +00:00
|
|
|
/* preview3 doesn't return any validators until there is a vote
|
2020-03-05 14:48:30 +00:00
|
|
|
check: func(t *testing.T, e *executor, validators interface{}) {
|
|
|
|
var expected []result.Validator
|
2020-06-23 15:15:55 +00:00
|
|
|
sBValidators := e.chain.GetStandByValidators()
|
2020-03-05 14:48:30 +00:00
|
|
|
for _, sbValidator := range sBValidators {
|
|
|
|
expected = append(expected, result.Validator{
|
|
|
|
PublicKey: *sbValidator,
|
|
|
|
Votes: 0,
|
|
|
|
Active: true,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
actual, ok := validators.(*[]result.Validator)
|
|
|
|
require.True(t, ok)
|
|
|
|
|
|
|
|
assert.ElementsMatch(t, expected, *actual)
|
|
|
|
},
|
2020-08-10 14:51:46 +00:00
|
|
|
*/
|
2020-03-05 14:48:30 +00:00
|
|
|
},
|
|
|
|
},
|
2019-11-21 16:41:28 +00:00
|
|
|
"getversion": {
|
|
|
|
{
|
|
|
|
params: "[]",
|
2020-02-21 12:10:59 +00:00
|
|
|
result: func(*executor) interface{} { return &result.Version{} },
|
|
|
|
check: func(t *testing.T, e *executor, ver interface{}) {
|
|
|
|
resp, ok := ver.(*result.Version)
|
2019-11-21 16:41:28 +00:00
|
|
|
require.True(t, ok)
|
2020-02-21 12:10:59 +00:00
|
|
|
require.Equal(t, "/NEO-GO:/", resp.UserAgent)
|
2019-11-21 16:41:28 +00:00
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
2019-11-26 10:13:17 +00:00
|
|
|
"invokefunction": {
|
2019-11-28 16:08:31 +00:00
|
|
|
{
|
|
|
|
name: "positive",
|
2019-11-26 10:13:17 +00:00
|
|
|
params: `["50befd26fdf6e4d957c11e078b24ebce6291456f", "test", []]`,
|
2020-03-03 10:08:34 +00:00
|
|
|
result: func(e *executor) interface{} { return &result.Invoke{} },
|
2020-02-21 12:10:59 +00:00
|
|
|
check: func(t *testing.T, e *executor, inv interface{}) {
|
2020-03-03 10:08:34 +00:00
|
|
|
res, ok := inv.(*result.Invoke)
|
2019-11-28 16:08:31 +00:00
|
|
|
require.True(t, ok)
|
2020-10-14 13:46:06 +00:00
|
|
|
assert.NotNil(t, res.Script)
|
2020-02-21 12:10:59 +00:00
|
|
|
assert.NotEqual(t, "", res.State)
|
|
|
|
assert.NotEqual(t, 0, res.GasConsumed)
|
2019-11-28 16:08:31 +00:00
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "no params",
|
|
|
|
params: `[]`,
|
|
|
|
fail: true,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "not a string",
|
2019-11-26 10:13:17 +00:00
|
|
|
params: `[42, "test", []]`,
|
2019-11-28 16:08:31 +00:00
|
|
|
fail: true,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "not a scripthash",
|
2019-11-26 10:13:17 +00:00
|
|
|
params: `["qwerty", "test", []]`,
|
2019-11-28 16:08:31 +00:00
|
|
|
fail: true,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "bad params",
|
2019-11-26 10:13:17 +00:00
|
|
|
params: `["50befd26fdf6e4d957c11e078b24ebce6291456f", "test", [{"type": "Integer", "value": "qwerty"}]]`,
|
2019-11-28 16:08:31 +00:00
|
|
|
fail: true,
|
|
|
|
},
|
|
|
|
},
|
2019-11-26 10:24:49 +00:00
|
|
|
"invokescript": {
|
2019-11-26 10:13:17 +00:00
|
|
|
{
|
|
|
|
name: "positive",
|
2020-10-14 13:46:06 +00:00
|
|
|
params: `["UcVrDUhlbGxvLCB3b3JsZCFoD05lby5SdW50aW1lLkxvZ2FsdWY="]`,
|
2020-03-03 10:08:34 +00:00
|
|
|
result: func(e *executor) interface{} { return &result.Invoke{} },
|
2020-02-21 12:10:59 +00:00
|
|
|
check: func(t *testing.T, e *executor, inv interface{}) {
|
2020-03-03 10:08:34 +00:00
|
|
|
res, ok := inv.(*result.Invoke)
|
2019-11-26 10:13:17 +00:00
|
|
|
require.True(t, ok)
|
2020-02-21 12:10:59 +00:00
|
|
|
assert.NotEqual(t, "", res.Script)
|
|
|
|
assert.NotEqual(t, "", res.State)
|
|
|
|
assert.NotEqual(t, 0, res.GasConsumed)
|
2019-11-26 10:13:17 +00:00
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
2020-06-10 11:45:55 +00:00
|
|
|
name: "positive, good witness",
|
2020-10-14 13:46:06 +00:00
|
|
|
// script is base64-encoded `test_verify.avm` representation, hashes are hex-encoded LE bytes of hashes used in the contract with `0x` prefix
|
|
|
|
params: fmt.Sprintf(`["%s",["0x0000000009070e030d0f0e020d0c06050e030c01","0x090c060e00010205040307030102000902030f0d"]]`, testVerifyContractAVM),
|
2020-06-10 11:45:55 +00:00
|
|
|
result: func(e *executor) interface{} { return &result.Invoke{} },
|
|
|
|
check: func(t *testing.T, e *executor, inv interface{}) {
|
|
|
|
res, ok := inv.(*result.Invoke)
|
|
|
|
require.True(t, ok)
|
|
|
|
assert.Equal(t, "HALT", res.State)
|
|
|
|
require.Equal(t, 1, len(res.Stack))
|
2020-07-31 12:26:28 +00:00
|
|
|
require.Equal(t, big.NewInt(3), res.Stack[0].Value())
|
2020-06-10 11:45:55 +00:00
|
|
|
},
|
2019-11-26 10:13:17 +00:00
|
|
|
},
|
|
|
|
{
|
2020-06-10 11:45:55 +00:00
|
|
|
name: "positive, bad witness of second hash",
|
2020-10-14 13:46:06 +00:00
|
|
|
params: fmt.Sprintf(`["%s",["0x0000000009070e030d0f0e020d0c06050e030c01"]]`, testVerifyContractAVM),
|
2020-06-10 11:45:55 +00:00
|
|
|
result: func(e *executor) interface{} { return &result.Invoke{} },
|
|
|
|
check: func(t *testing.T, e *executor, inv interface{}) {
|
|
|
|
res, ok := inv.(*result.Invoke)
|
|
|
|
require.True(t, ok)
|
|
|
|
assert.Equal(t, "HALT", res.State)
|
|
|
|
require.Equal(t, 1, len(res.Stack))
|
2020-07-31 12:26:28 +00:00
|
|
|
require.Equal(t, big.NewInt(2), res.Stack[0].Value())
|
2020-06-10 11:45:55 +00:00
|
|
|
},
|
2019-11-26 10:13:17 +00:00
|
|
|
},
|
|
|
|
{
|
2020-06-10 11:45:55 +00:00
|
|
|
name: "positive, no good hashes",
|
2020-10-14 13:46:06 +00:00
|
|
|
params: fmt.Sprintf(`["%s"]`, testVerifyContractAVM),
|
2020-06-10 11:45:55 +00:00
|
|
|
result: func(e *executor) interface{} { return &result.Invoke{} },
|
|
|
|
check: func(t *testing.T, e *executor, inv interface{}) {
|
|
|
|
res, ok := inv.(*result.Invoke)
|
|
|
|
require.True(t, ok)
|
|
|
|
assert.Equal(t, "HALT", res.State)
|
|
|
|
require.Equal(t, 1, len(res.Stack))
|
2020-07-31 12:26:28 +00:00
|
|
|
require.Equal(t, big.NewInt(1), res.Stack[0].Value())
|
2020-06-10 11:45:55 +00:00
|
|
|
},
|
2019-11-26 10:13:17 +00:00
|
|
|
},
|
2019-11-26 10:24:49 +00:00
|
|
|
{
|
2020-06-10 11:45:55 +00:00
|
|
|
name: "positive, bad hashes witness",
|
2020-10-14 13:46:06 +00:00
|
|
|
params: fmt.Sprintf(`["%s",["0x0000000009070e030d0f0e020d0c06050e030c02"]]`, testVerifyContractAVM),
|
2020-03-03 10:08:34 +00:00
|
|
|
result: func(e *executor) interface{} { return &result.Invoke{} },
|
2020-02-21 12:10:59 +00:00
|
|
|
check: func(t *testing.T, e *executor, inv interface{}) {
|
2020-03-03 10:08:34 +00:00
|
|
|
res, ok := inv.(*result.Invoke)
|
2019-11-26 10:24:49 +00:00
|
|
|
require.True(t, ok)
|
2020-06-10 11:45:55 +00:00
|
|
|
assert.Equal(t, "HALT", res.State)
|
|
|
|
assert.Equal(t, 1, len(res.Stack))
|
2020-07-31 12:26:28 +00:00
|
|
|
assert.Equal(t, big.NewInt(1), res.Stack[0].Value())
|
2019-11-26 10:24:49 +00:00
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "no params",
|
|
|
|
params: `[]`,
|
|
|
|
fail: true,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "not a string",
|
|
|
|
params: `[42]`,
|
|
|
|
fail: true,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "bas string",
|
|
|
|
params: `["qwerty"]`,
|
|
|
|
fail: true,
|
|
|
|
},
|
|
|
|
},
|
2020-12-14 12:23:39 +00:00
|
|
|
"invokecontractverify": {
|
|
|
|
{
|
|
|
|
name: "positive",
|
|
|
|
params: fmt.Sprintf(`["%s", [], [{"account":"%s"}]]`, verifyContractHash, testchain.PrivateKeyByID(0).PublicKey().GetScriptHash().StringLE()),
|
|
|
|
result: func(e *executor) interface{} { return &result.Invoke{} },
|
|
|
|
check: func(t *testing.T, e *executor, inv interface{}) {
|
|
|
|
res, ok := inv.(*result.Invoke)
|
|
|
|
require.True(t, ok)
|
|
|
|
assert.NotNil(t, res.Script)
|
|
|
|
assert.Equal(t, "HALT", res.State)
|
|
|
|
assert.NotEqual(t, 0, res.GasConsumed)
|
|
|
|
assert.Equal(t, true, res.Stack[0].Value().(bool))
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "positive, no signers",
|
|
|
|
params: fmt.Sprintf(`["%s", []]`, verifyContractHash),
|
|
|
|
result: func(e *executor) interface{} { return &result.Invoke{} },
|
|
|
|
check: func(t *testing.T, e *executor, inv interface{}) {
|
|
|
|
res, ok := inv.(*result.Invoke)
|
|
|
|
require.True(t, ok)
|
|
|
|
assert.NotNil(t, res.Script)
|
|
|
|
assert.Equal(t, "HALT", res.State, res.FaultException)
|
|
|
|
assert.NotEqual(t, 0, res.GasConsumed)
|
|
|
|
assert.Equal(t, false, res.Stack[0].Value().(bool))
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "positive, with scripts",
|
|
|
|
params: fmt.Sprintf(`["%s", [], [{"account":"%s", "invocation":"MQo=", "verification": ""}]]`, verifyContractHash, testchain.PrivateKeyByID(0).PublicKey().GetScriptHash().StringLE()),
|
|
|
|
result: func(e *executor) interface{} { return &result.Invoke{} },
|
|
|
|
check: func(t *testing.T, e *executor, inv interface{}) {
|
|
|
|
res, ok := inv.(*result.Invoke)
|
|
|
|
require.True(t, ok)
|
|
|
|
assert.NotNil(t, res.Script)
|
|
|
|
assert.Equal(t, "HALT", res.State)
|
|
|
|
assert.NotEqual(t, 0, res.GasConsumed)
|
|
|
|
assert.Equal(t, true, res.Stack[0].Value().(bool))
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "unknown contract",
|
|
|
|
params: fmt.Sprintf(`["%s", []]`, util.Uint160{}.String()),
|
|
|
|
fail: true,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "no params",
|
|
|
|
params: `[]`,
|
|
|
|
fail: true,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "not a string",
|
|
|
|
params: `[42, []]`,
|
|
|
|
fail: true,
|
|
|
|
},
|
|
|
|
},
|
2019-11-21 16:41:28 +00:00
|
|
|
"sendrawtransaction": {
|
|
|
|
{
|
|
|
|
name: "positive",
|
2020-11-12 11:05:20 +00:00
|
|
|
params: `["AAsAAACAlpgAAAAAACYcEwAAAAAAsAQAAAGqis+FnU/kArNOZz8hVoIXlqSI6wEAXQMA6HZIFwAAAAwUeLpMJACf5RDhNsmZWi4FIV4b5NwMFKqKz4WdT+QCs05nPyFWgheWpIjrE8AMCHRyYW5zZmVyDBQlBZ7LSHjTqHX5HFHO3tMw1Fdf3kFifVtSOAFCDEDqL1as9/ZGKdySLWWmAXbzljr9S3wlnyAXo6UTk0b46lRwRiRZCDKst3lAaaspg93IYrA7ajPUQozUxFy8CUHCKQwhArNiK/QBe9/jF8WK7V9MdT8ga324lgRvp9d0u8S/f43CC0GVRA14"]`,
|
2020-07-21 07:31:45 +00:00
|
|
|
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)
|
2020-09-30 10:50:58 +00:00
|
|
|
expectedHash, err := util.Uint256DecodeStringLE("ab5573cfc8d70774f04aa7d5521350cfc1aa1239c44c24e490e139408cd46a57")
|
2020-07-21 07:31:45 +00:00
|
|
|
require.NoError(t, err)
|
|
|
|
assert.Equal(t, expectedHash, res.Hash)
|
2019-11-21 16:41:28 +00:00
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "negative",
|
2020-11-12 11:05:20 +00:00
|
|
|
params: `["AAoAAAAxboUQOQGdOd/Cw31sP+4Z/VgJhwAAAAAAAAAA8q0FAAAAAACwBAAAAAExboUQOQGdOd/Cw31sP+4Z/VgJhwFdAwDodkgXAAAADBQgcoJ0r6/Db0OgcdMoz6PmKdnLsAwUMW6FEDkBnTnfwsN9bD/uGf1YCYcTwAwIdHJhbnNmZXIMFIl3INjNdvTwCr+jfA7diJwgj96bQWJ9W1I4AUIMQN+VMUEnEWlCHOurXSegFj4pTXx/LQUltEmHRTRIFP09bFxZHJsXI9BdQoVvQJrbCEz2esySHPr8YpEzpeteen4pDCECs2Ir9AF73+MXxYrtX0x1PyBrfbiWBG+n13S7xL9/jcILQQqQav8="]`,
|
2019-11-21 16:41:28 +00:00
|
|
|
fail: true,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "no params",
|
|
|
|
params: `[]`,
|
|
|
|
fail: true,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "invalid string",
|
2020-11-12 11:05:20 +00:00
|
|
|
params: `["notabase64%"]`,
|
2019-11-21 16:41:28 +00:00
|
|
|
fail: true,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "invalid tx",
|
2020-11-12 11:05:20 +00:00
|
|
|
params: `["AnTXkgcmF3IGNvbnRyYWNw=="]`,
|
2019-11-21 16:41:28 +00:00
|
|
|
fail: true,
|
|
|
|
},
|
|
|
|
},
|
2020-03-02 17:01:32 +00:00
|
|
|
"submitblock": {
|
|
|
|
{
|
2020-11-12 11:05:20 +00:00
|
|
|
name: "invalid base64",
|
|
|
|
params: `["%%%"]`,
|
2020-03-02 17:01:32 +00:00
|
|
|
fail: true,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "invalid block bytes",
|
2020-11-12 11:05:20 +00:00
|
|
|
params: `["AAAAACc="]`,
|
2020-03-02 17:01:32 +00:00
|
|
|
fail: true,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "no params",
|
|
|
|
params: `[]`,
|
|
|
|
fail: true,
|
|
|
|
},
|
|
|
|
},
|
2020-09-28 11:58:04 +00:00
|
|
|
"submitoracleresponse": {
|
|
|
|
{
|
|
|
|
name: "no params",
|
|
|
|
params: `[]`,
|
|
|
|
fail: true,
|
|
|
|
},
|
|
|
|
},
|
2021-02-09 09:05:45 +00:00
|
|
|
"submitnotaryrequest": {
|
|
|
|
{
|
|
|
|
name: "no params",
|
|
|
|
params: `[]`,
|
|
|
|
fail: true,
|
|
|
|
},
|
|
|
|
},
|
2019-11-21 16:41:28 +00:00
|
|
|
"validateaddress": {
|
|
|
|
{
|
|
|
|
name: "positive",
|
2020-06-16 10:47:29 +00:00
|
|
|
params: `["Nbb1qkwcwNSBs9pAnrVVrnFbWnbWBk91U2"]`,
|
2020-02-21 12:10:59 +00:00
|
|
|
result: func(*executor) interface{} { return &result.ValidateAddress{} },
|
|
|
|
check: func(t *testing.T, e *executor, va interface{}) {
|
|
|
|
res, ok := va.(*result.ValidateAddress)
|
2019-11-21 16:41:28 +00:00
|
|
|
require.True(t, ok)
|
2020-06-16 10:47:29 +00:00
|
|
|
assert.Equal(t, "Nbb1qkwcwNSBs9pAnrVVrnFbWnbWBk91U2", res.Address)
|
2020-02-21 12:10:59 +00:00
|
|
|
assert.True(t, res.IsValid)
|
2019-11-21 16:41:28 +00:00
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "negative",
|
|
|
|
params: "[1]",
|
|
|
|
result: func(*executor) interface{} {
|
2020-02-21 12:10:59 +00:00
|
|
|
return &result.ValidateAddress{
|
|
|
|
Address: float64(1),
|
|
|
|
IsValid: false,
|
2019-11-21 16:41:28 +00:00
|
|
|
}
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
2019-01-22 12:14:52 +00:00
|
|
|
|
2019-11-21 16:41:28 +00:00
|
|
|
func TestRPC(t *testing.T) {
|
2020-04-29 12:25:58 +00:00
|
|
|
t.Run("http", func(t *testing.T) {
|
|
|
|
testRPCProtocol(t, doRPCCallOverHTTP)
|
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("websocket", func(t *testing.T) {
|
|
|
|
testRPCProtocol(t, doRPCCallOverWS)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2020-09-28 11:58:04 +00:00
|
|
|
func TestSubmitOracle(t *testing.T) {
|
2021-02-09 09:05:45 +00:00
|
|
|
chain, rpcSrv, httpSrv := initClearServerWithServices(t, true, false)
|
2020-09-28 11:58:04 +00:00
|
|
|
defer chain.Close()
|
|
|
|
defer rpcSrv.Shutdown()
|
|
|
|
|
|
|
|
rpc := `{"jsonrpc": "2.0", "id": 1, "method": "submitoracleresponse", "params": %s}`
|
|
|
|
runCase := func(t *testing.T, fail bool, params ...string) func(t *testing.T) {
|
|
|
|
return func(t *testing.T) {
|
|
|
|
ps := `[` + strings.Join(params, ",") + `]`
|
|
|
|
req := fmt.Sprintf(rpc, ps)
|
|
|
|
body := doRPCCallOverHTTP(req, httpSrv.URL, t)
|
|
|
|
checkErrGetResult(t, body, fail)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
t.Run("MissingKey", runCase(t, true))
|
|
|
|
t.Run("InvalidKey", runCase(t, true, `"1234"`))
|
|
|
|
|
|
|
|
priv, err := keys.NewPrivateKey()
|
|
|
|
require.NoError(t, err)
|
|
|
|
pubStr := `"` + base64.StdEncoding.EncodeToString(priv.PublicKey().Bytes()) + `"`
|
|
|
|
t.Run("InvalidReqID", runCase(t, true, pubStr, `"notanumber"`))
|
|
|
|
t.Run("InvalidTxSignature", runCase(t, true, pubStr, `1`, `"qwerty"`))
|
|
|
|
|
|
|
|
txSig := priv.Sign([]byte{1, 2, 3})
|
|
|
|
txSigStr := `"` + base64.StdEncoding.EncodeToString(txSig) + `"`
|
|
|
|
t.Run("MissingMsgSignature", runCase(t, true, pubStr, `1`, txSigStr))
|
|
|
|
t.Run("InvalidMsgSignature", runCase(t, true, pubStr, `1`, txSigStr, `"0123"`))
|
|
|
|
|
|
|
|
msg := rpc2.GetMessage(priv.PublicKey().Bytes(), 1, txSig)
|
|
|
|
msgSigStr := `"` + base64.StdEncoding.EncodeToString(priv.Sign(msg)) + `"`
|
|
|
|
t.Run("Valid", runCase(t, false, pubStr, `1`, txSigStr, msgSigStr))
|
|
|
|
}
|
|
|
|
|
2021-02-09 09:05:45 +00:00
|
|
|
func TestSubmitNotaryRequest(t *testing.T) {
|
|
|
|
rpc := `{"jsonrpc": "2.0", "id": 1, "method": "submitnotaryrequest", "params": %s}`
|
|
|
|
|
|
|
|
t.Run("disabled P2PSigExtensions", func(t *testing.T) {
|
|
|
|
chain, rpcSrv, httpSrv := initClearServerWithServices(t, false, false)
|
|
|
|
defer chain.Close()
|
|
|
|
defer rpcSrv.Shutdown()
|
|
|
|
req := fmt.Sprintf(rpc, "[]")
|
|
|
|
body := doRPCCallOverHTTP(req, httpSrv.URL, t)
|
|
|
|
checkErrGetResult(t, body, true)
|
|
|
|
})
|
|
|
|
|
|
|
|
chain, rpcSrv, httpSrv := initServerWithInMemoryChainAndServices(t, false, true)
|
|
|
|
defer chain.Close()
|
|
|
|
defer rpcSrv.Shutdown()
|
|
|
|
|
|
|
|
runCase := func(t *testing.T, fail bool, params ...string) func(t *testing.T) {
|
|
|
|
return func(t *testing.T) {
|
|
|
|
ps := `[` + strings.Join(params, ",") + `]`
|
|
|
|
req := fmt.Sprintf(rpc, ps)
|
|
|
|
body := doRPCCallOverHTTP(req, httpSrv.URL, t)
|
|
|
|
checkErrGetResult(t, body, fail)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
t.Run("missing request", runCase(t, true))
|
|
|
|
t.Run("not a base64", runCase(t, true, `"not-a-base64$"`))
|
|
|
|
t.Run("invalid request bytes", runCase(t, true, `"not-a-request"`))
|
|
|
|
t.Run("invalid request", func(t *testing.T) {
|
|
|
|
mainTx := &transaction.Transaction{
|
|
|
|
Network: netmode.UnitTestNet,
|
|
|
|
Attributes: []transaction.Attribute{{Type: transaction.NotaryAssistedT, Value: &transaction.NotaryAssisted{NKeys: 1}}},
|
|
|
|
Script: []byte{byte(opcode.RET)},
|
|
|
|
ValidUntilBlock: 123,
|
|
|
|
Signers: []transaction.Signer{{Account: util.Uint160{1, 5, 9}}},
|
|
|
|
Scripts: []transaction.Witness{{
|
|
|
|
InvocationScript: []byte{1, 4, 7},
|
|
|
|
VerificationScript: []byte{3, 6, 9},
|
|
|
|
}},
|
|
|
|
}
|
|
|
|
fallbackTx := &transaction.Transaction{
|
|
|
|
Network: netmode.UnitTestNet,
|
|
|
|
Script: []byte{byte(opcode.RET)},
|
|
|
|
ValidUntilBlock: 123,
|
|
|
|
Attributes: []transaction.Attribute{
|
|
|
|
{Type: transaction.NotValidBeforeT, Value: &transaction.NotValidBefore{Height: 123}},
|
|
|
|
{Type: transaction.ConflictsT, Value: &transaction.Conflicts{Hash: mainTx.Hash()}},
|
|
|
|
{Type: transaction.NotaryAssistedT, Value: &transaction.NotaryAssisted{NKeys: 0}},
|
|
|
|
},
|
|
|
|
Signers: []transaction.Signer{{Account: util.Uint160{1, 4, 7}}, {Account: util.Uint160{9, 8, 7}}},
|
|
|
|
Scripts: []transaction.Witness{
|
|
|
|
{InvocationScript: append([]byte{byte(opcode.PUSHDATA1), 64}, make([]byte, 64, 64)...), VerificationScript: make([]byte, 0)},
|
|
|
|
{InvocationScript: []byte{1, 2, 3}, VerificationScript: []byte{1, 2, 3}}},
|
|
|
|
}
|
|
|
|
p := &payload.P2PNotaryRequest{
|
|
|
|
Network: netmode.UnitTestNet,
|
|
|
|
MainTransaction: mainTx,
|
|
|
|
FallbackTransaction: fallbackTx,
|
|
|
|
Witness: transaction.Witness{
|
|
|
|
InvocationScript: []byte{1, 2, 3},
|
|
|
|
VerificationScript: []byte{7, 8, 9},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
bytes, err := p.Bytes()
|
|
|
|
require.NoError(t, err)
|
|
|
|
str := fmt.Sprintf(`"%s"`, base64.StdEncoding.EncodeToString(bytes))
|
|
|
|
runCase(t, true, str)(t)
|
|
|
|
})
|
|
|
|
t.Run("valid request", func(t *testing.T) {
|
|
|
|
sender := testchain.PrivateKeyByID(0) // owner of the deposit in testchain
|
|
|
|
mainTx := &transaction.Transaction{
|
|
|
|
Network: netmode.UnitTestNet,
|
|
|
|
Attributes: []transaction.Attribute{{Type: transaction.NotaryAssistedT, Value: &transaction.NotaryAssisted{NKeys: 1}}},
|
|
|
|
Script: []byte{byte(opcode.RET)},
|
|
|
|
ValidUntilBlock: 123,
|
|
|
|
Signers: []transaction.Signer{{Account: util.Uint160{1, 5, 9}}},
|
|
|
|
Scripts: []transaction.Witness{{
|
|
|
|
InvocationScript: []byte{1, 4, 7},
|
|
|
|
VerificationScript: []byte{3, 6, 9},
|
|
|
|
}},
|
|
|
|
}
|
|
|
|
fallbackTx := &transaction.Transaction{
|
|
|
|
Network: netmode.UnitTestNet,
|
|
|
|
Script: []byte{byte(opcode.RET)},
|
|
|
|
ValidUntilBlock: 123,
|
|
|
|
Attributes: []transaction.Attribute{
|
|
|
|
{Type: transaction.NotValidBeforeT, Value: &transaction.NotValidBefore{Height: 123}},
|
|
|
|
{Type: transaction.ConflictsT, Value: &transaction.Conflicts{Hash: mainTx.Hash()}},
|
|
|
|
{Type: transaction.NotaryAssistedT, Value: &transaction.NotaryAssisted{NKeys: 0}},
|
|
|
|
},
|
|
|
|
Signers: []transaction.Signer{{Account: chain.GetNotaryContractScriptHash()}, {Account: sender.GetScriptHash()}},
|
|
|
|
Scripts: []transaction.Witness{
|
|
|
|
{InvocationScript: append([]byte{byte(opcode.PUSHDATA1), 64}, make([]byte, 64, 64)...), VerificationScript: []byte{}},
|
|
|
|
},
|
|
|
|
NetworkFee: 2_0000_0000,
|
|
|
|
}
|
|
|
|
fallbackTx.Scripts = append(fallbackTx.Scripts, transaction.Witness{
|
|
|
|
InvocationScript: append([]byte{byte(opcode.PUSHDATA1), 64}, sender.Sign(fallbackTx.GetSignedPart())...),
|
|
|
|
VerificationScript: sender.PublicKey().GetVerificationScript(),
|
|
|
|
})
|
|
|
|
p := &payload.P2PNotaryRequest{
|
|
|
|
Network: netmode.UnitTestNet,
|
|
|
|
MainTransaction: mainTx,
|
|
|
|
FallbackTransaction: fallbackTx,
|
|
|
|
}
|
|
|
|
p.Witness = transaction.Witness{
|
|
|
|
InvocationScript: append([]byte{byte(opcode.PUSHDATA1), 64}, sender.Sign(p.GetSignedPart())...),
|
|
|
|
VerificationScript: sender.PublicKey().GetVerificationScript(),
|
|
|
|
}
|
|
|
|
bytes, err := p.Bytes()
|
|
|
|
require.NoError(t, err)
|
|
|
|
str := fmt.Sprintf(`"%s"`, base64.StdEncoding.EncodeToString(bytes))
|
|
|
|
runCase(t, false, str)(t)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2020-04-29 12:25:58 +00:00
|
|
|
// testRPCProtocol runs a full set of tests using given callback to make actual
|
|
|
|
// calls. Some tests change the chain state, thus we reinitialize the chain from
|
|
|
|
// scratch here.
|
|
|
|
func testRPCProtocol(t *testing.T, doRPCCall func(string, string, *testing.T) []byte) {
|
2020-05-09 20:59:21 +00:00
|
|
|
chain, rpcSrv, httpSrv := initServerWithInMemoryChain(t)
|
2019-01-22 12:14:52 +00:00
|
|
|
|
2020-01-10 08:47:55 +00:00
|
|
|
defer chain.Close()
|
2020-05-09 20:59:21 +00:00
|
|
|
defer rpcSrv.Shutdown()
|
2020-01-10 08:47:55 +00:00
|
|
|
|
2020-04-29 12:14:56 +00:00
|
|
|
e := &executor{chain: chain, httpSrv: httpSrv}
|
2020-10-26 17:22:20 +00:00
|
|
|
t.Run("single request", func(t *testing.T) {
|
|
|
|
for method, cases := range rpcTestCases {
|
|
|
|
t.Run(method, func(t *testing.T) {
|
|
|
|
rpc := `{"jsonrpc": "2.0", "id": 1, "method": "%s", "params": %s}`
|
2019-01-22 12:14:52 +00:00
|
|
|
|
2020-10-26 17:22:20 +00:00
|
|
|
for _, tc := range cases {
|
|
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
|
|
body := doRPCCall(fmt.Sprintf(rpc, method, tc.params), httpSrv.URL, t)
|
|
|
|
result := checkErrGetResult(t, body, tc.fail)
|
|
|
|
if tc.fail {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
expected, res := tc.getResultPair(e)
|
|
|
|
err := json.Unmarshal(result, res)
|
|
|
|
require.NoErrorf(t, err, "could not parse response: %s", result)
|
|
|
|
|
|
|
|
if tc.check == nil {
|
|
|
|
assert.Equal(t, expected, res)
|
|
|
|
} else {
|
|
|
|
tc.check(t, e, res)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
})
|
|
|
|
t.Run("batch with single request", func(t *testing.T) {
|
|
|
|
for method, cases := range rpcTestCases {
|
|
|
|
if method == "sendrawtransaction" {
|
|
|
|
continue // cannot send the same transaction twice
|
|
|
|
}
|
|
|
|
t.Run(method, func(t *testing.T) {
|
|
|
|
rpc := `[{"jsonrpc": "2.0", "id": 1, "method": "%s", "params": %s}]`
|
|
|
|
|
|
|
|
for _, tc := range cases {
|
|
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
|
|
body := doRPCCall(fmt.Sprintf(rpc, method, tc.params), httpSrv.URL, t)
|
|
|
|
result := checkErrGetBatchResult(t, body, tc.fail)
|
|
|
|
if tc.fail {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
expected, res := tc.getResultPair(e)
|
|
|
|
err := json.Unmarshal(result, res)
|
|
|
|
require.NoErrorf(t, err, "could not parse response: %s", result)
|
|
|
|
|
|
|
|
if tc.check == nil {
|
|
|
|
assert.Equal(t, expected, res)
|
|
|
|
} else {
|
|
|
|
tc.check(t, e, res)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("batch with multiple requests", func(t *testing.T) {
|
|
|
|
for method, cases := range rpcTestCases {
|
|
|
|
if method == "sendrawtransaction" {
|
|
|
|
continue // cannot send the same transaction twice
|
|
|
|
}
|
|
|
|
t.Run(method, func(t *testing.T) {
|
|
|
|
rpc := `{"jsonrpc": "2.0", "id": %d, "method": "%s", "params": %s},`
|
|
|
|
var resultRPC string
|
|
|
|
for i, tc := range cases {
|
|
|
|
resultRPC += fmt.Sprintf(rpc, i, method, tc.params)
|
|
|
|
}
|
|
|
|
resultRPC = `[` + resultRPC[:len(resultRPC)-1] + `]`
|
|
|
|
body := doRPCCall(resultRPC, httpSrv.URL, t)
|
|
|
|
var responses []response.Raw
|
|
|
|
err := json.Unmarshal(body, &responses)
|
|
|
|
require.Nil(t, err)
|
|
|
|
for i, tc := range cases {
|
|
|
|
var resp response.Raw
|
|
|
|
for _, r := range responses {
|
|
|
|
if bytes.Equal(r.ID, []byte(strconv.Itoa(i))) {
|
|
|
|
resp = r
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if tc.fail {
|
|
|
|
require.NotNil(t, resp.Error)
|
|
|
|
assert.NotEqual(t, 0, resp.Error.Code)
|
|
|
|
assert.NotEqual(t, "", resp.Error.Message)
|
|
|
|
} else {
|
|
|
|
assert.Nil(t, resp.Error)
|
|
|
|
}
|
2019-11-21 16:41:28 +00:00
|
|
|
if tc.fail {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
expected, res := tc.getResultPair(e)
|
2020-10-26 17:22:20 +00:00
|
|
|
err := json.Unmarshal(resp.Result, res)
|
|
|
|
require.NoErrorf(t, err, "could not parse response: %s", resp.Result)
|
2019-02-20 17:39:32 +00:00
|
|
|
|
2019-11-21 16:41:28 +00:00
|
|
|
if tc.check == nil {
|
|
|
|
assert.Equal(t, expected, res)
|
|
|
|
} else {
|
|
|
|
tc.check(t, e, res)
|
|
|
|
}
|
2020-10-26 17:22:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
})
|
|
|
|
}
|
|
|
|
})
|
2019-11-15 19:04:10 +00:00
|
|
|
|
2020-06-18 20:09:24 +00:00
|
|
|
t.Run("getapplicationlog for block", func(t *testing.T) {
|
|
|
|
rpc := `{"jsonrpc": "2.0", "id": 1, "method": "getapplicationlog", "params": ["%s"]}`
|
|
|
|
body := doRPCCall(fmt.Sprintf(rpc, e.chain.GetHeaderHash(1).StringLE()), httpSrv.URL, t)
|
|
|
|
data := checkErrGetResult(t, body, false)
|
2020-11-11 15:43:28 +00:00
|
|
|
var res result.ApplicationLog
|
2020-06-18 20:09:24 +00:00
|
|
|
require.NoError(t, json.Unmarshal(data, &res))
|
2020-11-11 15:43:28 +00:00
|
|
|
require.Equal(t, 2, len(res.Executions))
|
|
|
|
require.Equal(t, trigger.OnPersist, res.Executions[0].Trigger)
|
|
|
|
require.Equal(t, vm.HaltState, res.Executions[0].VMState)
|
|
|
|
require.Equal(t, trigger.PostPersist, res.Executions[1].Trigger)
|
|
|
|
require.Equal(t, vm.HaltState, res.Executions[1].VMState)
|
2020-06-18 20:09:24 +00:00
|
|
|
})
|
|
|
|
|
2020-04-23 13:32:53 +00:00
|
|
|
t.Run("submit", func(t *testing.T) {
|
|
|
|
rpc := `{"jsonrpc": "2.0", "id": 1, "method": "submitblock", "params": ["%s"]}`
|
2020-05-06 10:11:28 +00:00
|
|
|
t.Run("invalid signature", func(t *testing.T) {
|
2020-08-20 15:47:14 +00:00
|
|
|
s := testchain.NewBlock(t, chain, 1, 0)
|
2020-05-06 10:11:28 +00:00
|
|
|
s.Script.VerificationScript[8] ^= 0xff
|
2020-05-04 13:53:36 +00:00
|
|
|
body := doRPCCall(fmt.Sprintf(rpc, encodeBlock(t, s)), httpSrv.URL, t)
|
2020-04-23 13:32:53 +00:00
|
|
|
checkErrGetResult(t, body, true)
|
|
|
|
})
|
|
|
|
|
2020-05-08 17:54:24 +00:00
|
|
|
priv0 := testchain.PrivateKeyByID(0)
|
2020-12-04 09:40:22 +00:00
|
|
|
acc0 := wallet.NewAccountFromPrivateKey(priv0)
|
2020-05-08 17:54:24 +00:00
|
|
|
|
|
|
|
addNetworkFee := func(tx *transaction.Transaction) {
|
|
|
|
size := io.GetVarSize(tx)
|
2020-12-11 12:22:49 +00:00
|
|
|
netFee, sizeDelta := fee.Calculate(chain.GetBaseExecFee(), acc0.Contract.Script)
|
2020-05-08 17:54:24 +00:00
|
|
|
tx.NetworkFee += netFee
|
|
|
|
size += sizeDelta
|
2020-06-23 14:15:35 +00:00
|
|
|
tx.NetworkFee += int64(size) * chain.FeePerByte()
|
2020-05-08 17:54:24 +00:00
|
|
|
}
|
|
|
|
|
2020-04-23 13:32:53 +00:00
|
|
|
newTx := func() *transaction.Transaction {
|
|
|
|
height := chain.BlockHeight()
|
2020-06-18 09:00:51 +00:00
|
|
|
tx := transaction.New(testchain.Network(), []byte{byte(opcode.PUSH1)}, 0)
|
2020-04-22 17:42:38 +00:00
|
|
|
tx.Nonce = height + 1
|
2020-04-23 13:32:53 +00:00
|
|
|
tx.ValidUntilBlock = height + 10
|
2020-07-29 16:57:38 +00:00
|
|
|
tx.Signers = []transaction.Signer{{Account: acc0.PrivateKey().GetScriptHash()}}
|
2020-05-08 17:54:24 +00:00
|
|
|
addNetworkFee(tx)
|
|
|
|
require.NoError(t, acc0.SignTx(tx))
|
2020-04-23 13:32:53 +00:00
|
|
|
return tx
|
|
|
|
}
|
|
|
|
|
|
|
|
t.Run("invalid height", func(t *testing.T) {
|
2020-08-20 15:47:14 +00:00
|
|
|
b := testchain.NewBlock(t, chain, 2, 0, newTx())
|
2020-04-29 12:14:56 +00:00
|
|
|
body := doRPCCall(fmt.Sprintf(rpc, encodeBlock(t, b)), httpSrv.URL, t)
|
2020-04-23 13:32:53 +00:00
|
|
|
checkErrGetResult(t, body, true)
|
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("positive", func(t *testing.T) {
|
2020-08-20 15:47:14 +00:00
|
|
|
b := testchain.NewBlock(t, chain, 1, 0, newTx())
|
2020-04-29 12:14:56 +00:00
|
|
|
body := doRPCCall(fmt.Sprintf(rpc, encodeBlock(t, b)), httpSrv.URL, t)
|
2020-04-23 13:32:53 +00:00
|
|
|
data := checkErrGetResult(t, body, false)
|
2020-07-21 07:41:18 +00:00
|
|
|
var res = new(result.RelayResult)
|
|
|
|
require.NoError(t, json.Unmarshal(data, res))
|
|
|
|
require.Equal(t, b.Hash(), res.Hash)
|
2020-04-23 13:32:53 +00:00
|
|
|
})
|
|
|
|
})
|
2020-06-05 08:51:39 +00:00
|
|
|
t.Run("getproof", func(t *testing.T) {
|
|
|
|
r, err := chain.GetStateRoot(3)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
rpc := fmt.Sprintf(`{"jsonrpc": "2.0", "id": 1, "method": "getproof", "params": ["%s", "%s", "%x"]}`,
|
|
|
|
r.Root.StringLE(), testContractHash, []byte("testkey"))
|
|
|
|
body := doRPCCall(rpc, httpSrv.URL, t)
|
|
|
|
rawRes := checkErrGetResult(t, body, false)
|
|
|
|
res := new(result.GetProof)
|
|
|
|
require.NoError(t, json.Unmarshal(rawRes, res))
|
|
|
|
require.True(t, res.Success)
|
|
|
|
h, _ := util.Uint160DecodeStringLE(testContractHash)
|
|
|
|
skey := makeStorageKey(chain.GetContractState(h).ID, []byte("testkey"))
|
|
|
|
require.Equal(t, skey, res.Result.Key)
|
|
|
|
require.True(t, len(res.Result.Proof) > 0)
|
|
|
|
|
|
|
|
rpc = fmt.Sprintf(`{"jsonrpc": "2.0", "id": 1, "method": "verifyproof", "params": ["%s", "%s"]}`,
|
|
|
|
r.Root.StringLE(), res.Result.String())
|
|
|
|
body = doRPCCall(rpc, httpSrv.URL, t)
|
|
|
|
rawRes = checkErrGetResult(t, body, false)
|
|
|
|
vp := new(result.VerifyProof)
|
|
|
|
require.NoError(t, json.Unmarshal(rawRes, vp))
|
|
|
|
require.Equal(t, []byte("testvalue"), vp.Value)
|
|
|
|
})
|
2020-06-03 15:09:36 +00:00
|
|
|
t.Run("getstateroot", func(t *testing.T) {
|
|
|
|
testRoot := func(t *testing.T, p string) {
|
|
|
|
rpc := fmt.Sprintf(`{"jsonrpc": "2.0", "id": 1, "method": "getstateroot", "params": [%s]}`, p)
|
|
|
|
body := doRPCCall(rpc, httpSrv.URL, t)
|
|
|
|
rawRes := checkErrGetResult(t, body, false)
|
|
|
|
|
|
|
|
res := new(state.MPTRootState)
|
|
|
|
require.NoError(t, json.Unmarshal(rawRes, res))
|
|
|
|
require.NotEqual(t, util.Uint256{}, res.Root) // be sure this test uses valid height
|
|
|
|
|
|
|
|
expected, err := e.chain.GetStateRoot(5)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, expected, res)
|
|
|
|
}
|
|
|
|
t.Run("ByHeight", func(t *testing.T) { testRoot(t, strconv.FormatInt(5, 10)) })
|
|
|
|
t.Run("ByHash", func(t *testing.T) { testRoot(t, `"`+chain.GetHeaderHash(5).StringLE()+`"`) })
|
|
|
|
})
|
2020-04-23 13:32:53 +00:00
|
|
|
|
2019-09-18 15:21:16 +00:00
|
|
|
t.Run("getrawtransaction", func(t *testing.T) {
|
2020-12-08 15:28:00 +00:00
|
|
|
block, _ := chain.GetBlock(chain.GetHeaderHash(1))
|
2020-06-05 13:07:04 +00:00
|
|
|
tx := block.Transactions[0]
|
|
|
|
rpc := fmt.Sprintf(`{"jsonrpc": "2.0", "id": 1, "method": "getrawtransaction", "params": ["%s"]}"`, tx.Hash().StringLE())
|
2020-04-29 12:14:56 +00:00
|
|
|
body := doRPCCall(rpc, httpSrv.URL, t)
|
2020-02-21 12:10:59 +00:00
|
|
|
result := checkErrGetResult(t, body, false)
|
|
|
|
var res string
|
|
|
|
err := json.Unmarshal(result, &res)
|
|
|
|
require.NoErrorf(t, err, "could not parse response: %s", result)
|
2020-06-05 13:07:04 +00:00
|
|
|
txBin, err := testserdes.EncodeBinary(tx)
|
|
|
|
require.NoError(t, err)
|
2020-11-06 14:37:58 +00:00
|
|
|
expected := base64.StdEncoding.EncodeToString(txBin)
|
2020-06-05 13:07:04 +00:00
|
|
|
assert.Equal(t, expected, res)
|
2019-09-18 15:21:16 +00:00
|
|
|
})
|
2019-01-22 12:14:52 +00:00
|
|
|
|
2019-11-21 16:41:28 +00:00
|
|
|
t.Run("getrawtransaction 2 arguments", func(t *testing.T) {
|
2020-12-08 15:28:00 +00:00
|
|
|
block, _ := chain.GetBlock(chain.GetHeaderHash(1))
|
2020-06-05 13:07:04 +00:00
|
|
|
tx := block.Transactions[0]
|
|
|
|
rpc := fmt.Sprintf(`{"jsonrpc": "2.0", "id": 1, "method": "getrawtransaction", "params": ["%s", 0]}"`, tx.Hash().StringLE())
|
2020-04-29 12:14:56 +00:00
|
|
|
body := doRPCCall(rpc, httpSrv.URL, t)
|
2020-02-21 12:10:59 +00:00
|
|
|
result := checkErrGetResult(t, body, false)
|
|
|
|
var res string
|
|
|
|
err := json.Unmarshal(result, &res)
|
|
|
|
require.NoErrorf(t, err, "could not parse response: %s", result)
|
2020-06-05 13:07:04 +00:00
|
|
|
txBin, err := testserdes.EncodeBinary(tx)
|
|
|
|
require.NoError(t, err)
|
2020-11-06 14:37:58 +00:00
|
|
|
expected := base64.StdEncoding.EncodeToString(txBin)
|
2020-06-05 13:07:04 +00:00
|
|
|
assert.Equal(t, expected, res)
|
2019-09-18 15:21:16 +00:00
|
|
|
})
|
2020-02-06 12:02:03 +00:00
|
|
|
|
2020-03-23 14:31:28 +00:00
|
|
|
t.Run("getrawtransaction 2 arguments, verbose", func(t *testing.T) {
|
2020-12-08 15:28:00 +00:00
|
|
|
block, _ := chain.GetBlock(chain.GetHeaderHash(1))
|
2020-04-22 17:42:38 +00:00
|
|
|
TXHash := block.Transactions[0].Hash()
|
2020-09-10 16:28:16 +00:00
|
|
|
_ = block.Transactions[0].Size()
|
2020-03-23 14:31:28 +00:00
|
|
|
rpc := fmt.Sprintf(`{"jsonrpc": "2.0", "id": 1, "method": "getrawtransaction", "params": ["%s", 1]}"`, TXHash.StringLE())
|
2020-04-29 12:14:56 +00:00
|
|
|
body := doRPCCall(rpc, httpSrv.URL, t)
|
2020-03-23 14:31:28 +00:00
|
|
|
txOut := checkErrGetResult(t, body, false)
|
2020-06-18 09:00:51 +00:00
|
|
|
actual := result.TransactionOutputRaw{Transaction: transaction.Transaction{Network: testchain.Network()}}
|
2020-03-23 14:31:28 +00:00
|
|
|
err := json.Unmarshal(txOut, &actual)
|
|
|
|
require.NoErrorf(t, err, "could not parse response: %s", txOut)
|
|
|
|
|
2020-06-18 08:47:54 +00:00
|
|
|
assert.Equal(t, *block.Transactions[0], actual.Transaction)
|
2021-02-09 09:05:45 +00:00
|
|
|
assert.Equal(t, 10, actual.Confirmations)
|
2020-03-23 14:31:28 +00:00
|
|
|
assert.Equal(t, TXHash, actual.Transaction.Hash())
|
|
|
|
})
|
|
|
|
|
2020-04-23 13:02:01 +00:00
|
|
|
t.Run("getblockheader_positive", func(t *testing.T) {
|
|
|
|
rpc := `{"jsonrpc": "2.0", "id": 1, "method": "getblockheader", "params": %s}`
|
|
|
|
testHeaderHash := chain.GetHeaderHash(1).StringLE()
|
|
|
|
hdr := e.getHeader(testHeaderHash)
|
|
|
|
|
|
|
|
runCase := func(t *testing.T, rpc string, expected, actual interface{}) {
|
2020-04-29 12:14:56 +00:00
|
|
|
body := doRPCCall(rpc, httpSrv.URL, t)
|
2020-04-23 13:02:01 +00:00
|
|
|
data := checkErrGetResult(t, body, false)
|
|
|
|
require.NoError(t, json.Unmarshal(data, actual))
|
|
|
|
require.Equal(t, expected, actual)
|
|
|
|
}
|
|
|
|
|
|
|
|
t.Run("no verbose", func(t *testing.T) {
|
|
|
|
w := io.NewBufBinWriter()
|
|
|
|
hdr.EncodeBinary(w.BinWriter)
|
|
|
|
require.NoError(t, w.Err)
|
2020-11-06 14:37:58 +00:00
|
|
|
encoded := base64.StdEncoding.EncodeToString(w.Bytes())
|
2020-04-23 13:02:01 +00:00
|
|
|
|
|
|
|
t.Run("missing", func(t *testing.T) {
|
|
|
|
runCase(t, fmt.Sprintf(rpc, `["`+testHeaderHash+`"]`), &encoded, new(string))
|
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("verbose=0", func(t *testing.T) {
|
|
|
|
runCase(t, fmt.Sprintf(rpc, `["`+testHeaderHash+`", 0]`), &encoded, new(string))
|
|
|
|
})
|
2020-06-05 13:02:55 +00:00
|
|
|
|
|
|
|
t.Run("by number", func(t *testing.T) {
|
|
|
|
runCase(t, fmt.Sprintf(rpc, `[1]`), &encoded, new(string))
|
|
|
|
})
|
2020-04-23 13:02:01 +00:00
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("verbose != 0", func(t *testing.T) {
|
|
|
|
nextHash := chain.GetHeaderHash(int(hdr.Index) + 1)
|
|
|
|
expected := &result.Header{
|
|
|
|
Hash: hdr.Hash(),
|
|
|
|
Size: io.GetVarSize(hdr),
|
|
|
|
Version: hdr.Version,
|
|
|
|
PrevBlockHash: hdr.PrevHash,
|
|
|
|
MerkleRoot: hdr.MerkleRoot,
|
|
|
|
Timestamp: hdr.Timestamp,
|
|
|
|
Index: hdr.Index,
|
|
|
|
NextConsensus: address.Uint160ToString(hdr.NextConsensus),
|
2020-05-25 13:41:39 +00:00
|
|
|
Witnesses: []transaction.Witness{hdr.Script},
|
2020-04-23 13:02:01 +00:00
|
|
|
Confirmations: e.chain.BlockHeight() - hdr.Index + 1,
|
|
|
|
NextBlockHash: &nextHash,
|
|
|
|
}
|
|
|
|
|
|
|
|
rpc := fmt.Sprintf(rpc, `["`+testHeaderHash+`", 2]`)
|
|
|
|
runCase(t, rpc, expected, new(result.Header))
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
2020-03-02 16:13:44 +00:00
|
|
|
t.Run("getrawmempool", func(t *testing.T) {
|
|
|
|
mp := chain.GetMemPool()
|
|
|
|
// `expected` stores hashes of previously added txs
|
|
|
|
expected := make([]util.Uint256, 0)
|
|
|
|
for _, tx := range mp.GetVerifiedTransactions() {
|
2020-06-05 16:01:10 +00:00
|
|
|
expected = append(expected, tx.Hash())
|
2020-03-02 16:13:44 +00:00
|
|
|
}
|
|
|
|
for i := 0; i < 5; i++ {
|
2020-06-18 09:00:51 +00:00
|
|
|
tx := transaction.New(testchain.Network(), []byte{byte(opcode.PUSH1)}, 0)
|
2020-07-29 16:57:38 +00:00
|
|
|
tx.Signers = []transaction.Signer{{Account: util.Uint160{1, 2, 3}}}
|
2020-03-02 16:13:44 +00:00
|
|
|
assert.NoError(t, mp.Add(tx, &FeerStub{}))
|
|
|
|
expected = append(expected, tx.Hash())
|
|
|
|
}
|
|
|
|
|
|
|
|
rpc := `{"jsonrpc": "2.0", "id": 1, "method": "getrawmempool", "params": []}`
|
2020-04-29 12:14:56 +00:00
|
|
|
body := doRPCCall(rpc, httpSrv.URL, t)
|
2020-03-02 16:13:44 +00:00
|
|
|
res := checkErrGetResult(t, body, false)
|
|
|
|
|
|
|
|
var actual []util.Uint256
|
|
|
|
err := json.Unmarshal(res, &actual)
|
|
|
|
require.NoErrorf(t, err, "could not parse response: %s", res)
|
|
|
|
|
|
|
|
assert.ElementsMatch(t, expected, actual)
|
|
|
|
})
|
2020-08-07 06:42:44 +00:00
|
|
|
|
2020-11-24 08:14:25 +00:00
|
|
|
t.Run("getnep17transfers", func(t *testing.T) {
|
|
|
|
testNEP17T := func(t *testing.T, start, stop, limit, page int, sent, rcvd []int) {
|
2020-09-12 21:12:45 +00:00
|
|
|
ps := []string{`"` + testchain.PrivateKeyByID(0).Address() + `"`}
|
|
|
|
if start != 0 {
|
|
|
|
h, err := e.chain.GetHeader(e.chain.GetHeaderHash(start))
|
|
|
|
var ts uint64
|
|
|
|
if err == nil {
|
|
|
|
ts = h.Timestamp
|
|
|
|
} else {
|
|
|
|
ts = uint64(time.Now().UnixNano() / 1_000_000)
|
|
|
|
}
|
|
|
|
ps = append(ps, strconv.FormatUint(ts, 10))
|
|
|
|
}
|
|
|
|
if stop != 0 {
|
|
|
|
h, err := e.chain.GetHeader(e.chain.GetHeaderHash(stop))
|
|
|
|
var ts uint64
|
|
|
|
if err == nil {
|
|
|
|
ts = h.Timestamp
|
|
|
|
} else {
|
|
|
|
ts = uint64(time.Now().UnixNano() / 1_000_000)
|
|
|
|
}
|
|
|
|
ps = append(ps, strconv.FormatUint(ts, 10))
|
|
|
|
}
|
|
|
|
if limit != 0 {
|
|
|
|
ps = append(ps, strconv.FormatInt(int64(limit), 10))
|
|
|
|
}
|
|
|
|
if page != 0 {
|
|
|
|
ps = append(ps, strconv.FormatInt(int64(page), 10))
|
|
|
|
}
|
|
|
|
p := strings.Join(ps, ", ")
|
2020-11-24 08:14:25 +00:00
|
|
|
rpc := fmt.Sprintf(`{"jsonrpc": "2.0", "id": 1, "method": "getnep17transfers", "params": [%s]}`, p)
|
2020-09-12 21:12:45 +00:00
|
|
|
body := doRPCCall(rpc, httpSrv.URL, t)
|
|
|
|
res := checkErrGetResult(t, body, false)
|
2020-11-24 08:14:25 +00:00
|
|
|
actual := new(result.NEP17Transfers)
|
2020-09-12 21:12:45 +00:00
|
|
|
require.NoError(t, json.Unmarshal(res, actual))
|
2020-11-24 08:14:25 +00:00
|
|
|
checkNep17TransfersAux(t, e, actual, sent, rcvd)
|
2020-09-12 21:12:45 +00:00
|
|
|
}
|
2021-02-09 09:05:45 +00:00
|
|
|
t.Run("time frame only", func(t *testing.T) { testNEP17T(t, 4, 5, 0, 0, []int{5, 6, 7, 8}, []int{1, 2}) })
|
2020-11-24 08:14:25 +00:00
|
|
|
t.Run("no res", func(t *testing.T) { testNEP17T(t, 100, 100, 0, 0, []int{}, []int{}) })
|
2021-02-09 09:05:45 +00:00
|
|
|
t.Run("limit", func(t *testing.T) { testNEP17T(t, 1, 7, 3, 0, []int{2, 3}, []int{0}) })
|
|
|
|
t.Run("limit 2", func(t *testing.T) { testNEP17T(t, 4, 5, 2, 0, []int{5}, []int{1}) })
|
|
|
|
t.Run("limit with page", func(t *testing.T) { testNEP17T(t, 1, 7, 3, 1, []int{4, 5}, []int{1}) })
|
|
|
|
t.Run("limit with page 2", func(t *testing.T) { testNEP17T(t, 1, 7, 3, 2, []int{6, 7}, []int{2}) })
|
2020-08-07 06:42:44 +00:00
|
|
|
})
|
2019-11-21 16:41:28 +00:00
|
|
|
}
|
2019-01-22 12:14:52 +00:00
|
|
|
|
2020-04-23 13:02:01 +00:00
|
|
|
func (e *executor) getHeader(s string) *block.Header {
|
|
|
|
hash, err := util.Uint256DecodeStringLE(s)
|
|
|
|
if err != nil {
|
|
|
|
panic("can not decode hash parameter")
|
|
|
|
}
|
|
|
|
block, err := e.chain.GetBlock(hash)
|
|
|
|
if err != nil {
|
|
|
|
panic("unknown block (update block hash)")
|
|
|
|
}
|
|
|
|
return block.Header()
|
|
|
|
}
|
|
|
|
|
2020-04-23 13:32:53 +00:00
|
|
|
func encodeBlock(t *testing.T, b *block.Block) string {
|
|
|
|
w := io.NewBufBinWriter()
|
|
|
|
b.EncodeBinary(w.BinWriter)
|
|
|
|
require.NoError(t, w.Err)
|
2020-11-12 11:05:20 +00:00
|
|
|
return base64.StdEncoding.EncodeToString(w.Bytes())
|
2020-04-23 13:32:53 +00:00
|
|
|
}
|
|
|
|
|
2019-11-21 16:41:28 +00:00
|
|
|
func (tc rpcTestCase) getResultPair(e *executor) (expected interface{}, res interface{}) {
|
|
|
|
expected = tc.result(e)
|
2020-02-21 12:10:59 +00:00
|
|
|
resVal := reflect.New(reflect.TypeOf(expected).Elem())
|
2020-06-18 09:00:51 +00:00
|
|
|
res = resVal.Interface()
|
|
|
|
switch r := res.(type) {
|
|
|
|
case *result.Block:
|
|
|
|
r.Network = testchain.Network()
|
|
|
|
}
|
|
|
|
return expected, res
|
2019-09-18 15:21:16 +00:00
|
|
|
}
|
2019-01-22 12:14:52 +00:00
|
|
|
|
2020-02-21 12:10:59 +00:00
|
|
|
func checkErrGetResult(t *testing.T, body []byte, expectingFail bool) json.RawMessage {
|
|
|
|
var resp response.Raw
|
|
|
|
err := json.Unmarshal(body, &resp)
|
2019-11-21 16:41:28 +00:00
|
|
|
require.Nil(t, err)
|
2019-09-24 15:47:23 +00:00
|
|
|
if expectingFail {
|
2020-05-06 10:10:32 +00:00
|
|
|
require.NotNil(t, resp.Error)
|
2020-02-21 12:10:59 +00:00
|
|
|
assert.NotEqual(t, 0, resp.Error.Code)
|
|
|
|
assert.NotEqual(t, "", resp.Error.Message)
|
2019-09-24 15:47:23 +00:00
|
|
|
} else {
|
2020-02-21 12:10:59 +00:00
|
|
|
assert.Nil(t, resp.Error)
|
2019-09-24 15:47:23 +00:00
|
|
|
}
|
2020-02-21 12:10:59 +00:00
|
|
|
return resp.Result
|
2019-09-24 15:47:23 +00:00
|
|
|
}
|
|
|
|
|
2020-10-26 17:22:20 +00:00
|
|
|
func checkErrGetBatchResult(t *testing.T, body []byte, expectingFail bool) json.RawMessage {
|
|
|
|
var resp []response.Raw
|
|
|
|
err := json.Unmarshal(body, &resp)
|
|
|
|
require.Nil(t, err)
|
|
|
|
require.Equal(t, 1, len(resp))
|
|
|
|
if expectingFail {
|
|
|
|
require.NotNil(t, resp[0].Error)
|
|
|
|
assert.NotEqual(t, 0, resp[0].Error.Code)
|
|
|
|
assert.NotEqual(t, "", resp[0].Error.Message)
|
|
|
|
} else {
|
|
|
|
assert.Nil(t, resp[0].Error)
|
|
|
|
}
|
|
|
|
return resp[0].Result
|
|
|
|
}
|
|
|
|
|
2020-04-29 12:25:58 +00:00
|
|
|
func doRPCCallOverWS(rpcCall string, url string, t *testing.T) []byte {
|
|
|
|
dialer := websocket.Dialer{HandshakeTimeout: time.Second}
|
|
|
|
url = "ws" + strings.TrimPrefix(url, "http")
|
|
|
|
c, _, err := dialer.Dial(url+"/ws", nil)
|
|
|
|
require.NoError(t, err)
|
|
|
|
c.SetWriteDeadline(time.Now().Add(time.Second))
|
|
|
|
require.NoError(t, c.WriteMessage(1, []byte(rpcCall)))
|
|
|
|
c.SetReadDeadline(time.Now().Add(time.Second))
|
|
|
|
_, body, err := c.ReadMessage()
|
|
|
|
require.NoError(t, err)
|
2020-09-16 09:51:59 +00:00
|
|
|
require.NoError(t, c.Close())
|
2020-04-29 12:25:58 +00:00
|
|
|
return bytes.TrimSpace(body)
|
|
|
|
}
|
|
|
|
|
|
|
|
func doRPCCallOverHTTP(rpcCall string, url string, t *testing.T) []byte {
|
2020-04-29 12:14:56 +00:00
|
|
|
cl := http.Client{Timeout: time.Second}
|
|
|
|
resp, err := cl.Post(url, "application/json", strings.NewReader(rpcCall))
|
|
|
|
require.NoErrorf(t, err, "could not make a POST request")
|
2019-09-18 15:21:16 +00:00
|
|
|
body, err := ioutil.ReadAll(resp.Body)
|
|
|
|
assert.NoErrorf(t, err, "could not read response from the request: %s", rpcCall)
|
2019-11-21 15:05:18 +00:00
|
|
|
return bytes.TrimSpace(body)
|
2019-01-22 12:14:52 +00:00
|
|
|
}
|
2020-07-03 15:10:07 +00:00
|
|
|
|
2020-11-24 08:14:25 +00:00
|
|
|
func checkNep17Balances(t *testing.T, e *executor, acc interface{}) {
|
|
|
|
res, ok := acc.(*result.NEP17Balances)
|
2020-07-03 15:10:07 +00:00
|
|
|
require.True(t, ok)
|
|
|
|
rubles, err := util.Uint160DecodeStringLE(testContractHash)
|
|
|
|
require.NoError(t, err)
|
2020-11-24 08:14:25 +00:00
|
|
|
expected := result.NEP17Balances{
|
|
|
|
Balances: []result.NEP17Balance{
|
2020-07-03 15:10:07 +00:00
|
|
|
{
|
|
|
|
Asset: rubles,
|
rpc: adjust NEP5 transfers amount JSON marshalling
This committ fixes the difference between Go and C# nodes:
Go:
```
{
"jsonrpc" : "2.0",
"result" : {
"received" : [
{
"blockindex" : 65,
"txhash" : "0x394f851cf167d664c0dbcf98e2e64f2da23022fd7943dcb914492529de20a945",
"transfernotifyindex" : 0,
"timestamp" : 1605535020126,
"transferaddress" : "NUVPACMnKFhpuHjsRjhUvXz1XhqfGZYVtY",
"amount" : "29999999",
"assethash" : "0x668e0c1f9d7b70a99dd9e06eadd4c784d641afbc"
}
],
"address" : "NULwe3UAHckN2fzNdcVg31tDiaYtMDwANt",
"sent" : []
},
"id" : 1
}
```
C#:
```
{
"id" : 1,
"result" : {
"address" : "NULwe3UAHckN2fzNdcVg31tDiaYtMDwANt",
"sent" : [],
"received" : [
{
"transferaddress" : "NUVPACMnKFhpuHjsRjhUvXz1XhqfGZYVtY",
"timestamp" : 1605535020126,
"txhash" : "0x394f851cf167d664c0dbcf98e2e64f2da23022fd7943dcb914492529de20a945",
"blockindex" : 65,
"transfernotifyindex" : 0,
"amount" : "2999999900000000",
"assethash" : "0x668e0c1f9d7b70a99dd9e06eadd4c784d641afbc"
}
]
},
"jsonrpc" : "2.0"
}
```
2020-11-17 09:28:28 +00:00
|
|
|
Amount: "877",
|
2020-07-03 15:10:07 +00:00
|
|
|
LastUpdated: 6,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Asset: e.chain.GoverningTokenHash(),
|
|
|
|
Amount: "99998000",
|
|
|
|
LastUpdated: 4,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Asset: e.chain.UtilityTokenHash(),
|
2021-02-09 09:05:45 +00:00
|
|
|
Amount: "78994306100",
|
|
|
|
LastUpdated: 8,
|
2020-07-03 15:10:07 +00:00
|
|
|
}},
|
|
|
|
Address: testchain.PrivateKeyByID(0).GetScriptHash().StringLE(),
|
|
|
|
}
|
|
|
|
require.Equal(t, testchain.PrivateKeyByID(0).Address(), res.Address)
|
|
|
|
require.ElementsMatch(t, expected.Balances, res.Balances)
|
|
|
|
}
|
2020-07-03 15:25:18 +00:00
|
|
|
|
2020-11-24 08:14:25 +00:00
|
|
|
func checkNep17Transfers(t *testing.T, e *executor, acc interface{}) {
|
2021-02-09 09:05:45 +00:00
|
|
|
checkNep17TransfersAux(t, e, acc, []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, []int{0, 1, 2, 3, 4, 5, 6})
|
2020-08-07 06:42:44 +00:00
|
|
|
}
|
|
|
|
|
2020-11-24 08:14:25 +00:00
|
|
|
func checkNep17TransfersAux(t *testing.T, e *executor, acc interface{}, sent, rcvd []int) {
|
|
|
|
res, ok := acc.(*result.NEP17Transfers)
|
2020-07-03 15:25:18 +00:00
|
|
|
require.True(t, ok)
|
|
|
|
rublesHash, err := util.Uint160DecodeStringLE(testContractHash)
|
|
|
|
require.NoError(t, err)
|
2020-09-12 21:12:45 +00:00
|
|
|
|
2021-02-09 09:05:45 +00:00
|
|
|
blockDepositGAS, err := e.chain.GetBlock(e.chain.GetHeaderHash(8))
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, 1, len(blockDepositGAS.Transactions))
|
|
|
|
txDepositGAS := blockDepositGAS.Transactions[0]
|
|
|
|
|
2020-09-12 21:12:45 +00:00
|
|
|
blockDeploy2, err := e.chain.GetBlock(e.chain.GetHeaderHash(7))
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, 1, len(blockDeploy2.Transactions))
|
|
|
|
txDeploy2 := blockDeploy2.Transactions[0]
|
|
|
|
|
2020-07-03 15:25:18 +00:00
|
|
|
blockSendRubles, err := e.chain.GetBlock(e.chain.GetHeaderHash(6))
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, 1, len(blockSendRubles.Transactions))
|
2020-09-12 21:12:45 +00:00
|
|
|
txSendRubles := blockSendRubles.Transactions[0]
|
2020-08-26 13:16:57 +00:00
|
|
|
blockGASBounty := blockSendRubles // index 6 = size of committee
|
2020-09-12 21:12:45 +00:00
|
|
|
|
2020-07-03 15:25:18 +00:00
|
|
|
blockReceiveRubles, err := e.chain.GetBlock(e.chain.GetHeaderHash(5))
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, 2, len(blockReceiveRubles.Transactions))
|
2020-09-12 21:12:45 +00:00
|
|
|
txInitCall := blockReceiveRubles.Transactions[0]
|
|
|
|
txReceiveRubles := blockReceiveRubles.Transactions[1]
|
|
|
|
|
2020-07-03 15:25:18 +00:00
|
|
|
blockSendNEO, err := e.chain.GetBlock(e.chain.GetHeaderHash(4))
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, 1, len(blockSendNEO.Transactions))
|
2020-09-12 21:12:45 +00:00
|
|
|
txSendNEO := blockSendNEO.Transactions[0]
|
|
|
|
|
|
|
|
blockCtrInv1, err := e.chain.GetBlock(e.chain.GetHeaderHash(3))
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, 1, len(blockCtrInv1.Transactions))
|
|
|
|
txCtrInv1 := blockCtrInv1.Transactions[0]
|
|
|
|
|
|
|
|
blockCtrDeploy, err := e.chain.GetBlock(e.chain.GetHeaderHash(2))
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, 1, len(blockCtrDeploy.Transactions))
|
|
|
|
txCtrDeploy := blockCtrDeploy.Transactions[0]
|
|
|
|
|
|
|
|
blockReceiveGAS, err := e.chain.GetBlock(e.chain.GetHeaderHash(1))
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, 2, len(blockReceiveGAS.Transactions))
|
|
|
|
txReceiveNEO := blockReceiveGAS.Transactions[0]
|
|
|
|
txReceiveGAS := blockReceiveGAS.Transactions[1]
|
|
|
|
|
2020-09-23 08:48:31 +00:00
|
|
|
blockGASBounty0, err := e.chain.GetBlock(e.chain.GetHeaderHash(0))
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
2020-09-12 21:12:45 +00:00
|
|
|
// These are laid out here explicitly for 2 purposes:
|
|
|
|
// * to be able to reference any particular event for paging
|
|
|
|
// * to check chain events consistency
|
|
|
|
// Technically these could be retrieved from application log, but that would almost
|
|
|
|
// duplicate the Server method.
|
2020-11-24 08:14:25 +00:00
|
|
|
expected := result.NEP17Transfers{
|
|
|
|
Sent: []result.NEP17Transfer{
|
2021-02-09 09:05:45 +00:00
|
|
|
{
|
|
|
|
Timestamp: blockDepositGAS.Timestamp,
|
|
|
|
Asset: e.chain.UtilityTokenHash(),
|
|
|
|
Address: address.Uint160ToString(e.chain.GetNotaryContractScriptHash()),
|
|
|
|
Amount: "1000000000",
|
|
|
|
Index: 8,
|
|
|
|
NotifyIndex: 0,
|
|
|
|
TxHash: txDepositGAS.Hash(),
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Timestamp: blockDepositGAS.Timestamp,
|
|
|
|
Asset: e.chain.UtilityTokenHash(),
|
|
|
|
Address: "", // burn
|
|
|
|
Amount: big.NewInt(txDepositGAS.SystemFee + txDepositGAS.NetworkFee).String(),
|
|
|
|
Index: 8,
|
|
|
|
TxHash: blockDepositGAS.Hash(),
|
|
|
|
},
|
2020-07-03 15:25:18 +00:00
|
|
|
{
|
2020-09-12 21:12:45 +00:00
|
|
|
Timestamp: blockDeploy2.Timestamp,
|
|
|
|
Asset: e.chain.UtilityTokenHash(),
|
|
|
|
Address: "", // burn
|
rpc: adjust NEP5 transfers amount JSON marshalling
This committ fixes the difference between Go and C# nodes:
Go:
```
{
"jsonrpc" : "2.0",
"result" : {
"received" : [
{
"blockindex" : 65,
"txhash" : "0x394f851cf167d664c0dbcf98e2e64f2da23022fd7943dcb914492529de20a945",
"transfernotifyindex" : 0,
"timestamp" : 1605535020126,
"transferaddress" : "NUVPACMnKFhpuHjsRjhUvXz1XhqfGZYVtY",
"amount" : "29999999",
"assethash" : "0x668e0c1f9d7b70a99dd9e06eadd4c784d641afbc"
}
],
"address" : "NULwe3UAHckN2fzNdcVg31tDiaYtMDwANt",
"sent" : []
},
"id" : 1
}
```
C#:
```
{
"id" : 1,
"result" : {
"address" : "NULwe3UAHckN2fzNdcVg31tDiaYtMDwANt",
"sent" : [],
"received" : [
{
"transferaddress" : "NUVPACMnKFhpuHjsRjhUvXz1XhqfGZYVtY",
"timestamp" : 1605535020126,
"txhash" : "0x394f851cf167d664c0dbcf98e2e64f2da23022fd7943dcb914492529de20a945",
"blockindex" : 65,
"transfernotifyindex" : 0,
"amount" : "2999999900000000",
"assethash" : "0x668e0c1f9d7b70a99dd9e06eadd4c784d641afbc"
}
]
},
"jsonrpc" : "2.0"
}
```
2020-11-17 09:28:28 +00:00
|
|
|
Amount: big.NewInt(txDeploy2.SystemFee + txDeploy2.NetworkFee).String(),
|
2020-09-12 21:12:45 +00:00
|
|
|
Index: 7,
|
|
|
|
TxHash: blockDeploy2.Hash(),
|
2020-07-03 15:25:18 +00:00
|
|
|
},
|
2020-08-07 06:42:44 +00:00
|
|
|
{
|
|
|
|
Timestamp: blockSendRubles.Timestamp,
|
|
|
|
Asset: rublesHash,
|
|
|
|
Address: testchain.PrivateKeyByID(1).Address(),
|
rpc: adjust NEP5 transfers amount JSON marshalling
This committ fixes the difference between Go and C# nodes:
Go:
```
{
"jsonrpc" : "2.0",
"result" : {
"received" : [
{
"blockindex" : 65,
"txhash" : "0x394f851cf167d664c0dbcf98e2e64f2da23022fd7943dcb914492529de20a945",
"transfernotifyindex" : 0,
"timestamp" : 1605535020126,
"transferaddress" : "NUVPACMnKFhpuHjsRjhUvXz1XhqfGZYVtY",
"amount" : "29999999",
"assethash" : "0x668e0c1f9d7b70a99dd9e06eadd4c784d641afbc"
}
],
"address" : "NULwe3UAHckN2fzNdcVg31tDiaYtMDwANt",
"sent" : []
},
"id" : 1
}
```
C#:
```
{
"id" : 1,
"result" : {
"address" : "NULwe3UAHckN2fzNdcVg31tDiaYtMDwANt",
"sent" : [],
"received" : [
{
"transferaddress" : "NUVPACMnKFhpuHjsRjhUvXz1XhqfGZYVtY",
"timestamp" : 1605535020126,
"txhash" : "0x394f851cf167d664c0dbcf98e2e64f2da23022fd7943dcb914492529de20a945",
"blockindex" : 65,
"transfernotifyindex" : 0,
"amount" : "2999999900000000",
"assethash" : "0x668e0c1f9d7b70a99dd9e06eadd4c784d641afbc"
}
]
},
"jsonrpc" : "2.0"
}
```
2020-11-17 09:28:28 +00:00
|
|
|
Amount: "123",
|
2020-08-07 06:42:44 +00:00
|
|
|
Index: 6,
|
|
|
|
NotifyIndex: 0,
|
2020-09-12 21:12:45 +00:00
|
|
|
TxHash: txSendRubles.Hash(),
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Timestamp: blockSendRubles.Timestamp,
|
|
|
|
Asset: e.chain.UtilityTokenHash(),
|
|
|
|
Address: "", // burn
|
rpc: adjust NEP5 transfers amount JSON marshalling
This committ fixes the difference between Go and C# nodes:
Go:
```
{
"jsonrpc" : "2.0",
"result" : {
"received" : [
{
"blockindex" : 65,
"txhash" : "0x394f851cf167d664c0dbcf98e2e64f2da23022fd7943dcb914492529de20a945",
"transfernotifyindex" : 0,
"timestamp" : 1605535020126,
"transferaddress" : "NUVPACMnKFhpuHjsRjhUvXz1XhqfGZYVtY",
"amount" : "29999999",
"assethash" : "0x668e0c1f9d7b70a99dd9e06eadd4c784d641afbc"
}
],
"address" : "NULwe3UAHckN2fzNdcVg31tDiaYtMDwANt",
"sent" : []
},
"id" : 1
}
```
C#:
```
{
"id" : 1,
"result" : {
"address" : "NULwe3UAHckN2fzNdcVg31tDiaYtMDwANt",
"sent" : [],
"received" : [
{
"transferaddress" : "NUVPACMnKFhpuHjsRjhUvXz1XhqfGZYVtY",
"timestamp" : 1605535020126,
"txhash" : "0x394f851cf167d664c0dbcf98e2e64f2da23022fd7943dcb914492529de20a945",
"blockindex" : 65,
"transfernotifyindex" : 0,
"amount" : "2999999900000000",
"assethash" : "0x668e0c1f9d7b70a99dd9e06eadd4c784d641afbc"
}
]
},
"jsonrpc" : "2.0"
}
```
2020-11-17 09:28:28 +00:00
|
|
|
Amount: big.NewInt(txSendRubles.SystemFee + txSendRubles.NetworkFee).String(),
|
2020-09-12 21:12:45 +00:00
|
|
|
Index: 6,
|
|
|
|
TxHash: blockSendRubles.Hash(),
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Timestamp: blockReceiveRubles.Timestamp,
|
|
|
|
Asset: e.chain.UtilityTokenHash(),
|
|
|
|
Address: "", // burn
|
rpc: adjust NEP5 transfers amount JSON marshalling
This committ fixes the difference between Go and C# nodes:
Go:
```
{
"jsonrpc" : "2.0",
"result" : {
"received" : [
{
"blockindex" : 65,
"txhash" : "0x394f851cf167d664c0dbcf98e2e64f2da23022fd7943dcb914492529de20a945",
"transfernotifyindex" : 0,
"timestamp" : 1605535020126,
"transferaddress" : "NUVPACMnKFhpuHjsRjhUvXz1XhqfGZYVtY",
"amount" : "29999999",
"assethash" : "0x668e0c1f9d7b70a99dd9e06eadd4c784d641afbc"
}
],
"address" : "NULwe3UAHckN2fzNdcVg31tDiaYtMDwANt",
"sent" : []
},
"id" : 1
}
```
C#:
```
{
"id" : 1,
"result" : {
"address" : "NULwe3UAHckN2fzNdcVg31tDiaYtMDwANt",
"sent" : [],
"received" : [
{
"transferaddress" : "NUVPACMnKFhpuHjsRjhUvXz1XhqfGZYVtY",
"timestamp" : 1605535020126,
"txhash" : "0x394f851cf167d664c0dbcf98e2e64f2da23022fd7943dcb914492529de20a945",
"blockindex" : 65,
"transfernotifyindex" : 0,
"amount" : "2999999900000000",
"assethash" : "0x668e0c1f9d7b70a99dd9e06eadd4c784d641afbc"
}
]
},
"jsonrpc" : "2.0"
}
```
2020-11-17 09:28:28 +00:00
|
|
|
Amount: big.NewInt(txReceiveRubles.SystemFee + txReceiveRubles.NetworkFee).String(),
|
2020-09-12 21:12:45 +00:00
|
|
|
Index: 5,
|
|
|
|
TxHash: blockReceiveRubles.Hash(),
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Timestamp: blockReceiveRubles.Timestamp,
|
|
|
|
Asset: e.chain.UtilityTokenHash(),
|
|
|
|
Address: "", // burn
|
rpc: adjust NEP5 transfers amount JSON marshalling
This committ fixes the difference between Go and C# nodes:
Go:
```
{
"jsonrpc" : "2.0",
"result" : {
"received" : [
{
"blockindex" : 65,
"txhash" : "0x394f851cf167d664c0dbcf98e2e64f2da23022fd7943dcb914492529de20a945",
"transfernotifyindex" : 0,
"timestamp" : 1605535020126,
"transferaddress" : "NUVPACMnKFhpuHjsRjhUvXz1XhqfGZYVtY",
"amount" : "29999999",
"assethash" : "0x668e0c1f9d7b70a99dd9e06eadd4c784d641afbc"
}
],
"address" : "NULwe3UAHckN2fzNdcVg31tDiaYtMDwANt",
"sent" : []
},
"id" : 1
}
```
C#:
```
{
"id" : 1,
"result" : {
"address" : "NULwe3UAHckN2fzNdcVg31tDiaYtMDwANt",
"sent" : [],
"received" : [
{
"transferaddress" : "NUVPACMnKFhpuHjsRjhUvXz1XhqfGZYVtY",
"timestamp" : 1605535020126,
"txhash" : "0x394f851cf167d664c0dbcf98e2e64f2da23022fd7943dcb914492529de20a945",
"blockindex" : 65,
"transfernotifyindex" : 0,
"amount" : "2999999900000000",
"assethash" : "0x668e0c1f9d7b70a99dd9e06eadd4c784d641afbc"
}
]
},
"jsonrpc" : "2.0"
}
```
2020-11-17 09:28:28 +00:00
|
|
|
Amount: big.NewInt(txInitCall.SystemFee + txInitCall.NetworkFee).String(),
|
2020-09-12 21:12:45 +00:00
|
|
|
Index: 5,
|
|
|
|
TxHash: blockReceiveRubles.Hash(),
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Timestamp: blockSendNEO.Timestamp,
|
|
|
|
Asset: e.chain.GoverningTokenHash(),
|
|
|
|
Address: testchain.PrivateKeyByID(1).Address(),
|
|
|
|
Amount: "1000",
|
|
|
|
Index: 4,
|
|
|
|
NotifyIndex: 0,
|
|
|
|
TxHash: txSendNEO.Hash(),
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Timestamp: blockSendNEO.Timestamp,
|
|
|
|
Asset: e.chain.UtilityTokenHash(),
|
|
|
|
Address: "", // burn
|
rpc: adjust NEP5 transfers amount JSON marshalling
This committ fixes the difference between Go and C# nodes:
Go:
```
{
"jsonrpc" : "2.0",
"result" : {
"received" : [
{
"blockindex" : 65,
"txhash" : "0x394f851cf167d664c0dbcf98e2e64f2da23022fd7943dcb914492529de20a945",
"transfernotifyindex" : 0,
"timestamp" : 1605535020126,
"transferaddress" : "NUVPACMnKFhpuHjsRjhUvXz1XhqfGZYVtY",
"amount" : "29999999",
"assethash" : "0x668e0c1f9d7b70a99dd9e06eadd4c784d641afbc"
}
],
"address" : "NULwe3UAHckN2fzNdcVg31tDiaYtMDwANt",
"sent" : []
},
"id" : 1
}
```
C#:
```
{
"id" : 1,
"result" : {
"address" : "NULwe3UAHckN2fzNdcVg31tDiaYtMDwANt",
"sent" : [],
"received" : [
{
"transferaddress" : "NUVPACMnKFhpuHjsRjhUvXz1XhqfGZYVtY",
"timestamp" : 1605535020126,
"txhash" : "0x394f851cf167d664c0dbcf98e2e64f2da23022fd7943dcb914492529de20a945",
"blockindex" : 65,
"transfernotifyindex" : 0,
"amount" : "2999999900000000",
"assethash" : "0x668e0c1f9d7b70a99dd9e06eadd4c784d641afbc"
}
]
},
"jsonrpc" : "2.0"
}
```
2020-11-17 09:28:28 +00:00
|
|
|
Amount: big.NewInt(txSendNEO.SystemFee + txSendNEO.NetworkFee).String(),
|
2020-09-12 21:12:45 +00:00
|
|
|
Index: 4,
|
|
|
|
TxHash: blockSendNEO.Hash(),
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Timestamp: blockCtrInv1.Timestamp,
|
|
|
|
Asset: e.chain.UtilityTokenHash(),
|
|
|
|
Address: "", // burn has empty receiver
|
rpc: adjust NEP5 transfers amount JSON marshalling
This committ fixes the difference between Go and C# nodes:
Go:
```
{
"jsonrpc" : "2.0",
"result" : {
"received" : [
{
"blockindex" : 65,
"txhash" : "0x394f851cf167d664c0dbcf98e2e64f2da23022fd7943dcb914492529de20a945",
"transfernotifyindex" : 0,
"timestamp" : 1605535020126,
"transferaddress" : "NUVPACMnKFhpuHjsRjhUvXz1XhqfGZYVtY",
"amount" : "29999999",
"assethash" : "0x668e0c1f9d7b70a99dd9e06eadd4c784d641afbc"
}
],
"address" : "NULwe3UAHckN2fzNdcVg31tDiaYtMDwANt",
"sent" : []
},
"id" : 1
}
```
C#:
```
{
"id" : 1,
"result" : {
"address" : "NULwe3UAHckN2fzNdcVg31tDiaYtMDwANt",
"sent" : [],
"received" : [
{
"transferaddress" : "NUVPACMnKFhpuHjsRjhUvXz1XhqfGZYVtY",
"timestamp" : 1605535020126,
"txhash" : "0x394f851cf167d664c0dbcf98e2e64f2da23022fd7943dcb914492529de20a945",
"blockindex" : 65,
"transfernotifyindex" : 0,
"amount" : "2999999900000000",
"assethash" : "0x668e0c1f9d7b70a99dd9e06eadd4c784d641afbc"
}
]
},
"jsonrpc" : "2.0"
}
```
2020-11-17 09:28:28 +00:00
|
|
|
Amount: big.NewInt(txCtrInv1.SystemFee + txCtrInv1.NetworkFee).String(),
|
2020-09-12 21:12:45 +00:00
|
|
|
Index: 3,
|
|
|
|
TxHash: blockCtrInv1.Hash(),
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Timestamp: blockCtrDeploy.Timestamp,
|
|
|
|
Asset: e.chain.UtilityTokenHash(),
|
|
|
|
Address: "", // burn has empty receiver
|
rpc: adjust NEP5 transfers amount JSON marshalling
This committ fixes the difference between Go and C# nodes:
Go:
```
{
"jsonrpc" : "2.0",
"result" : {
"received" : [
{
"blockindex" : 65,
"txhash" : "0x394f851cf167d664c0dbcf98e2e64f2da23022fd7943dcb914492529de20a945",
"transfernotifyindex" : 0,
"timestamp" : 1605535020126,
"transferaddress" : "NUVPACMnKFhpuHjsRjhUvXz1XhqfGZYVtY",
"amount" : "29999999",
"assethash" : "0x668e0c1f9d7b70a99dd9e06eadd4c784d641afbc"
}
],
"address" : "NULwe3UAHckN2fzNdcVg31tDiaYtMDwANt",
"sent" : []
},
"id" : 1
}
```
C#:
```
{
"id" : 1,
"result" : {
"address" : "NULwe3UAHckN2fzNdcVg31tDiaYtMDwANt",
"sent" : [],
"received" : [
{
"transferaddress" : "NUVPACMnKFhpuHjsRjhUvXz1XhqfGZYVtY",
"timestamp" : 1605535020126,
"txhash" : "0x394f851cf167d664c0dbcf98e2e64f2da23022fd7943dcb914492529de20a945",
"blockindex" : 65,
"transfernotifyindex" : 0,
"amount" : "2999999900000000",
"assethash" : "0x668e0c1f9d7b70a99dd9e06eadd4c784d641afbc"
}
]
},
"jsonrpc" : "2.0"
}
```
2020-11-17 09:28:28 +00:00
|
|
|
Amount: big.NewInt(txCtrDeploy.SystemFee + txCtrDeploy.NetworkFee).String(),
|
2020-09-12 21:12:45 +00:00
|
|
|
Index: 2,
|
|
|
|
TxHash: blockCtrDeploy.Hash(),
|
2020-08-07 06:42:44 +00:00
|
|
|
},
|
2020-07-03 15:25:18 +00:00
|
|
|
},
|
2020-11-24 08:14:25 +00:00
|
|
|
Received: []result.NEP17Transfer{
|
2020-08-26 13:16:57 +00:00
|
|
|
{
|
|
|
|
Timestamp: blockGASBounty.Timestamp,
|
|
|
|
Asset: e.chain.UtilityTokenHash(),
|
|
|
|
Address: "",
|
rpc: adjust NEP5 transfers amount JSON marshalling
This committ fixes the difference between Go and C# nodes:
Go:
```
{
"jsonrpc" : "2.0",
"result" : {
"received" : [
{
"blockindex" : 65,
"txhash" : "0x394f851cf167d664c0dbcf98e2e64f2da23022fd7943dcb914492529de20a945",
"transfernotifyindex" : 0,
"timestamp" : 1605535020126,
"transferaddress" : "NUVPACMnKFhpuHjsRjhUvXz1XhqfGZYVtY",
"amount" : "29999999",
"assethash" : "0x668e0c1f9d7b70a99dd9e06eadd4c784d641afbc"
}
],
"address" : "NULwe3UAHckN2fzNdcVg31tDiaYtMDwANt",
"sent" : []
},
"id" : 1
}
```
C#:
```
{
"id" : 1,
"result" : {
"address" : "NULwe3UAHckN2fzNdcVg31tDiaYtMDwANt",
"sent" : [],
"received" : [
{
"transferaddress" : "NUVPACMnKFhpuHjsRjhUvXz1XhqfGZYVtY",
"timestamp" : 1605535020126,
"txhash" : "0x394f851cf167d664c0dbcf98e2e64f2da23022fd7943dcb914492529de20a945",
"blockindex" : 65,
"transfernotifyindex" : 0,
"amount" : "2999999900000000",
"assethash" : "0x668e0c1f9d7b70a99dd9e06eadd4c784d641afbc"
}
]
},
"jsonrpc" : "2.0"
}
```
2020-11-17 09:28:28 +00:00
|
|
|
Amount: "50000000",
|
2020-08-26 13:16:57 +00:00
|
|
|
Index: 6,
|
|
|
|
NotifyIndex: 0,
|
|
|
|
TxHash: blockGASBounty.Hash(),
|
|
|
|
},
|
2020-07-03 15:25:18 +00:00
|
|
|
{
|
|
|
|
Timestamp: blockReceiveRubles.Timestamp,
|
|
|
|
Asset: rublesHash,
|
|
|
|
Address: address.Uint160ToString(rublesHash),
|
rpc: adjust NEP5 transfers amount JSON marshalling
This committ fixes the difference between Go and C# nodes:
Go:
```
{
"jsonrpc" : "2.0",
"result" : {
"received" : [
{
"blockindex" : 65,
"txhash" : "0x394f851cf167d664c0dbcf98e2e64f2da23022fd7943dcb914492529de20a945",
"transfernotifyindex" : 0,
"timestamp" : 1605535020126,
"transferaddress" : "NUVPACMnKFhpuHjsRjhUvXz1XhqfGZYVtY",
"amount" : "29999999",
"assethash" : "0x668e0c1f9d7b70a99dd9e06eadd4c784d641afbc"
}
],
"address" : "NULwe3UAHckN2fzNdcVg31tDiaYtMDwANt",
"sent" : []
},
"id" : 1
}
```
C#:
```
{
"id" : 1,
"result" : {
"address" : "NULwe3UAHckN2fzNdcVg31tDiaYtMDwANt",
"sent" : [],
"received" : [
{
"transferaddress" : "NUVPACMnKFhpuHjsRjhUvXz1XhqfGZYVtY",
"timestamp" : 1605535020126,
"txhash" : "0x394f851cf167d664c0dbcf98e2e64f2da23022fd7943dcb914492529de20a945",
"blockindex" : 65,
"transfernotifyindex" : 0,
"amount" : "2999999900000000",
"assethash" : "0x668e0c1f9d7b70a99dd9e06eadd4c784d641afbc"
}
]
},
"jsonrpc" : "2.0"
}
```
2020-11-17 09:28:28 +00:00
|
|
|
Amount: "1000",
|
2020-07-03 15:25:18 +00:00
|
|
|
Index: 5,
|
|
|
|
NotifyIndex: 0,
|
2020-09-12 21:12:45 +00:00
|
|
|
TxHash: txReceiveRubles.Hash(),
|
2020-07-03 15:25:18 +00:00
|
|
|
},
|
|
|
|
{
|
|
|
|
Timestamp: blockSendNEO.Timestamp,
|
|
|
|
Asset: e.chain.UtilityTokenHash(),
|
|
|
|
Address: "", // Minted GAS.
|
rpc: adjust NEP5 transfers amount JSON marshalling
This committ fixes the difference between Go and C# nodes:
Go:
```
{
"jsonrpc" : "2.0",
"result" : {
"received" : [
{
"blockindex" : 65,
"txhash" : "0x394f851cf167d664c0dbcf98e2e64f2da23022fd7943dcb914492529de20a945",
"transfernotifyindex" : 0,
"timestamp" : 1605535020126,
"transferaddress" : "NUVPACMnKFhpuHjsRjhUvXz1XhqfGZYVtY",
"amount" : "29999999",
"assethash" : "0x668e0c1f9d7b70a99dd9e06eadd4c784d641afbc"
}
],
"address" : "NULwe3UAHckN2fzNdcVg31tDiaYtMDwANt",
"sent" : []
},
"id" : 1
}
```
C#:
```
{
"id" : 1,
"result" : {
"address" : "NULwe3UAHckN2fzNdcVg31tDiaYtMDwANt",
"sent" : [],
"received" : [
{
"transferaddress" : "NUVPACMnKFhpuHjsRjhUvXz1XhqfGZYVtY",
"timestamp" : 1605535020126,
"txhash" : "0x394f851cf167d664c0dbcf98e2e64f2da23022fd7943dcb914492529de20a945",
"blockindex" : 65,
"transfernotifyindex" : 0,
"amount" : "2999999900000000",
"assethash" : "0x668e0c1f9d7b70a99dd9e06eadd4c784d641afbc"
}
]
},
"jsonrpc" : "2.0"
}
```
2020-11-17 09:28:28 +00:00
|
|
|
Amount: "149998500",
|
2020-07-03 15:25:18 +00:00
|
|
|
Index: 4,
|
|
|
|
NotifyIndex: 0,
|
2020-09-12 21:12:45 +00:00
|
|
|
TxHash: txSendNEO.Hash(),
|
2020-07-03 15:25:18 +00:00
|
|
|
},
|
|
|
|
{
|
|
|
|
Timestamp: blockReceiveGAS.Timestamp,
|
|
|
|
Asset: e.chain.UtilityTokenHash(),
|
|
|
|
Address: testchain.MultisigAddress(),
|
rpc: adjust NEP5 transfers amount JSON marshalling
This committ fixes the difference between Go and C# nodes:
Go:
```
{
"jsonrpc" : "2.0",
"result" : {
"received" : [
{
"blockindex" : 65,
"txhash" : "0x394f851cf167d664c0dbcf98e2e64f2da23022fd7943dcb914492529de20a945",
"transfernotifyindex" : 0,
"timestamp" : 1605535020126,
"transferaddress" : "NUVPACMnKFhpuHjsRjhUvXz1XhqfGZYVtY",
"amount" : "29999999",
"assethash" : "0x668e0c1f9d7b70a99dd9e06eadd4c784d641afbc"
}
],
"address" : "NULwe3UAHckN2fzNdcVg31tDiaYtMDwANt",
"sent" : []
},
"id" : 1
}
```
C#:
```
{
"id" : 1,
"result" : {
"address" : "NULwe3UAHckN2fzNdcVg31tDiaYtMDwANt",
"sent" : [],
"received" : [
{
"transferaddress" : "NUVPACMnKFhpuHjsRjhUvXz1XhqfGZYVtY",
"timestamp" : 1605535020126,
"txhash" : "0x394f851cf167d664c0dbcf98e2e64f2da23022fd7943dcb914492529de20a945",
"blockindex" : 65,
"transfernotifyindex" : 0,
"amount" : "2999999900000000",
"assethash" : "0x668e0c1f9d7b70a99dd9e06eadd4c784d641afbc"
}
]
},
"jsonrpc" : "2.0"
}
```
2020-11-17 09:28:28 +00:00
|
|
|
Amount: "100000000000",
|
2020-07-03 15:25:18 +00:00
|
|
|
Index: 1,
|
|
|
|
NotifyIndex: 0,
|
2020-09-12 21:12:45 +00:00
|
|
|
TxHash: txReceiveGAS.Hash(),
|
2020-07-03 15:25:18 +00:00
|
|
|
},
|
|
|
|
{
|
|
|
|
Timestamp: blockReceiveGAS.Timestamp,
|
|
|
|
Asset: e.chain.GoverningTokenHash(),
|
|
|
|
Address: testchain.MultisigAddress(),
|
|
|
|
Amount: "99999000",
|
|
|
|
Index: 1,
|
|
|
|
NotifyIndex: 0,
|
2020-09-12 21:12:45 +00:00
|
|
|
TxHash: txReceiveNEO.Hash(),
|
2020-07-03 15:25:18 +00:00
|
|
|
},
|
2020-09-23 08:48:31 +00:00
|
|
|
{
|
|
|
|
Timestamp: blockGASBounty0.Timestamp,
|
|
|
|
Asset: e.chain.UtilityTokenHash(),
|
|
|
|
Address: "",
|
rpc: adjust NEP5 transfers amount JSON marshalling
This committ fixes the difference between Go and C# nodes:
Go:
```
{
"jsonrpc" : "2.0",
"result" : {
"received" : [
{
"blockindex" : 65,
"txhash" : "0x394f851cf167d664c0dbcf98e2e64f2da23022fd7943dcb914492529de20a945",
"transfernotifyindex" : 0,
"timestamp" : 1605535020126,
"transferaddress" : "NUVPACMnKFhpuHjsRjhUvXz1XhqfGZYVtY",
"amount" : "29999999",
"assethash" : "0x668e0c1f9d7b70a99dd9e06eadd4c784d641afbc"
}
],
"address" : "NULwe3UAHckN2fzNdcVg31tDiaYtMDwANt",
"sent" : []
},
"id" : 1
}
```
C#:
```
{
"id" : 1,
"result" : {
"address" : "NULwe3UAHckN2fzNdcVg31tDiaYtMDwANt",
"sent" : [],
"received" : [
{
"transferaddress" : "NUVPACMnKFhpuHjsRjhUvXz1XhqfGZYVtY",
"timestamp" : 1605535020126,
"txhash" : "0x394f851cf167d664c0dbcf98e2e64f2da23022fd7943dcb914492529de20a945",
"blockindex" : 65,
"transfernotifyindex" : 0,
"amount" : "2999999900000000",
"assethash" : "0x668e0c1f9d7b70a99dd9e06eadd4c784d641afbc"
}
]
},
"jsonrpc" : "2.0"
}
```
2020-11-17 09:28:28 +00:00
|
|
|
Amount: "50000000",
|
2020-09-23 08:48:31 +00:00
|
|
|
Index: 0,
|
|
|
|
TxHash: blockGASBounty0.Hash(),
|
|
|
|
},
|
2020-07-03 15:25:18 +00:00
|
|
|
},
|
|
|
|
Address: testchain.PrivateKeyByID(0).Address(),
|
|
|
|
}
|
|
|
|
|
|
|
|
require.Equal(t, expected.Address, res.Address)
|
2020-08-07 06:42:44 +00:00
|
|
|
|
2020-11-24 08:14:25 +00:00
|
|
|
arr := make([]result.NEP17Transfer, 0, len(expected.Sent))
|
2020-08-07 06:42:44 +00:00
|
|
|
for i := range expected.Sent {
|
2020-09-12 21:12:45 +00:00
|
|
|
for _, j := range sent {
|
|
|
|
if i == j {
|
|
|
|
arr = append(arr, expected.Sent[i])
|
|
|
|
break
|
|
|
|
}
|
2020-08-07 06:42:44 +00:00
|
|
|
}
|
|
|
|
}
|
2020-09-12 21:12:45 +00:00
|
|
|
require.Equal(t, arr, res.Sent)
|
2020-08-07 06:42:44 +00:00
|
|
|
|
|
|
|
arr = arr[:0]
|
|
|
|
for i := range expected.Received {
|
2020-09-12 21:12:45 +00:00
|
|
|
for _, j := range rcvd {
|
|
|
|
if i == j {
|
|
|
|
arr = append(arr, expected.Received[i])
|
|
|
|
break
|
|
|
|
}
|
2020-08-07 06:42:44 +00:00
|
|
|
}
|
|
|
|
}
|
2020-09-12 21:12:45 +00:00
|
|
|
require.Equal(t, arr, res.Received)
|
2020-07-03 15:25:18 +00:00
|
|
|
}
|