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-03-05 07:18:03 +00:00
const testContractHash = "1e1c3024bd955ff3baf7cb92e3b7608c7bb3712b"
2021-03-09 15:11:21 +00:00
const deploymentTxHash = "7cf43b182dee2e8bd2c5209cd230799aeba1b5b13000db682d917c89eacd1eae"
const genesisBlockHash = "d237e3500d8b4cf0df3fd9c4c053016afae141207a6c732303bdd91aff444ecc"
2020-08-24 11:00:05 +00:00
2021-03-05 07:18:03 +00:00
const verifyContractHash = "5bb4bac40e961e334ba7bd36d2496010f67e246e"
const verifyContractAVM = "VwMAQS1RCDAhcAwUVVQtU+0PVUb61E1umZEoZwIvzl7bMHFoE87bKGnbKJdA"
const invokescriptContractAVM = "VwcADBQBDAMOBQYMDQIODw0DDgcJAAAAANswcGhB+CfsjCGqJgQRQAwUDQ8DAgkAAgEDBwMEBQIBAA4GDAnbMHFpQfgn7IwhqiYEEkATQA=="
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-15 15:43:10 +00:00
assert . Equal ( t , int32 ( - 7 ) , 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" ,
2021-03-05 07:18:03 +00:00
// script is base64-encoded `invokescript_contract.avm` representation, hashes are hex-encoded LE bytes of hashes used in the contract with `0x` prefix
params : fmt . Sprintf ( ` ["%s",["0x0000000009070e030d0f0e020d0c06050e030c01","0x090c060e00010205040307030102000902030f0d"]] ` , invokescriptContractAVM ) ,
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" ,
2021-03-05 07:18:03 +00:00
params : fmt . Sprintf ( ` ["%s",["0x0000000009070e030d0f0e020d0c06050e030c01"]] ` , invokescriptContractAVM ) ,
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" ,
2021-03-05 07:18:03 +00:00
params : fmt . Sprintf ( ` ["%s"] ` , invokescriptContractAVM ) ,
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" ,
2021-03-05 07:18:03 +00:00
params : fmt . Sprintf ( ` ["%s",["0x0000000009070e030d0f0e020d0c06050e030c02"]] ` , invokescriptContractAVM ) ,
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 )
2021-03-05 07:18:03 +00:00
assert . Equal ( t , true , res . Stack [ 0 ] . Value ( ) . ( bool ) , fmt . Sprintf ( "check address in verification_contract.go: expected %s" , testchain . PrivateKeyByID ( 0 ) . Address ( ) ) )
2020-12-14 12:23:39 +00:00
} ,
} ,
{
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" ,
2021-03-05 07:18:03 +00:00
params : ` ["ADQSAADA2KcAAAAAABDiEgAAAAAAgBYAAAFVVC1T7Q9VRvrUTW6ZkShnAi/OXgEAYBDAAwDodkgXAAAADBRdSe/t0S4+BgGLRljbEKiXX8gLTgwUVVQtU+0PVUb61E1umZEoZwIvzl4UwB8MCHRyYW5zZmVyDBT1Y+pAvCg9TQ4FxI6jBbPyoHNA70FifVtSOQFCDEAppqgOf7RZvrS+uOVzVNlcQAQnyujtzHzv9/Za+FFkxWFd8mZ6AvWnFXAL0W5NafW4xyP7Kp/qgWCmZrHINaLkKAwhArNiK/QBe9/jF8WK7V9MdT8ga324lgRvp9d0u8S/f43CQXR0dqo="] ` ,
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 )
2021-03-05 07:18:03 +00:00
expectedHash , err := util . Uint256DecodeStringLE ( "3b133d0c2912da4f99680ae3a5f0e178bc761f2c360662a1fabbe1a8dbe309ea" )
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 ) {
2021-01-29 14:33:24 +00:00
r , err := chain . GetStateModule ( ) . GetStateRoot ( 3 )
2020-06-05 08:51:39 +00:00
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 )
2021-01-29 14:33:24 +00:00
res := new ( state . MPTRoot )
2020-06-03 15:09:36 +00:00
require . NoError ( t , json . Unmarshal ( rawRes , res ) )
require . NotEqual ( t , util . Uint256 { } , res . Root ) // be sure this test uses valid height
2021-01-29 14:33:24 +00:00
expected , err := e . chain . GetStateModule ( ) . GetStateRoot ( 5 )
2020-06-03 15:09:36 +00:00
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)" )
}
2021-03-01 13:44:47 +00:00
return & block . Header
2020-04-23 13:02:01 +00:00
}
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-03-05 07:18:03 +00:00
Amount : "78994302340" ,
2021-02-09 09:05:45 +00:00
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
}