diff --git a/cli/wallet/wallet.go b/cli/wallet/wallet.go index d3992d5c1..547e0e52a 100644 --- a/cli/wallet/wallet.go +++ b/cli/wallet/wallet.go @@ -264,6 +264,11 @@ func claimGas(ctx *cli.Context) error { } tx := transaction.NewClaimTX(&claim) + validUntilBlock, err := c.CalculateValidUntilBlock() + if err != nil { + return cli.NewExitError(err, 1) + } + tx.ValidUntilBlock = validUntilBlock tx.AddOutput(&transaction.Output{ AssetID: core.UtilityTokenID(), @@ -510,6 +515,11 @@ func transferAsset(ctx *cli.Context) error { } tx := transaction.NewContractTX() + validUntilBlock, err := c.CalculateValidUntilBlock() + if err != nil { + return cli.NewExitError(err, 1) + } + tx.ValidUntilBlock = validUntilBlock if err := request.AddInputsAndUnspentsToTx(tx, fromFlag.String(), asset, amount, c); err != nil { return cli.NewExitError(err, 1) } diff --git a/pkg/consensus/consensus_test.go b/pkg/consensus/consensus_test.go index 640c31399..6db174f3e 100644 --- a/pkg/consensus/consensus_test.go +++ b/pkg/consensus/consensus_test.go @@ -19,6 +19,7 @@ import ( func TestNewService(t *testing.T) { srv := newTestService(t) tx := transaction.NewMinerTX() + tx.ValidUntilBlock = 1 require.NoError(t, srv.Chain.PoolTx(tx)) var txx []block.Transaction @@ -30,11 +31,11 @@ func TestNewService(t *testing.T) { func TestService_GetVerified(t *testing.T) { srv := newTestService(t) - txs := []*transaction.Transaction{ - transaction.NewMinerTXWithNonce(123), - transaction.NewMinerTXWithNonce(124), - transaction.NewMinerTXWithNonce(125), - transaction.NewMinerTXWithNonce(126), + var txs []*transaction.Transaction + for i := 0; i < 4; i++ { + tx := transaction.NewMinerTXWithNonce(123 + uint32(i)) + tx.ValidUntilBlock = 1 + txs = append(txs, tx) } require.NoError(t, srv.Chain.PoolTx(txs[3])) @@ -107,6 +108,7 @@ func TestService_getTx(t *testing.T) { t.Run("transaction in mempool", func(t *testing.T) { tx := transaction.NewMinerTXWithNonce(1234) + tx.ValidUntilBlock = 1 h := tx.Hash() require.Equal(t, nil, srv.getTx(h)) @@ -120,6 +122,7 @@ func TestService_getTx(t *testing.T) { t.Run("transaction in local cache", func(t *testing.T) { tx := transaction.NewMinerTXWithNonce(4321) + tx.ValidUntilBlock = 1 h := tx.Hash() require.Equal(t, nil, srv.getTx(h)) diff --git a/pkg/consensus/payload_test.go b/pkg/consensus/payload_test.go index 949f5a5c5..9d993850b 100644 --- a/pkg/consensus/payload_test.go +++ b/pkg/consensus/payload_test.go @@ -1,7 +1,6 @@ package consensus import ( - "encoding/hex" "math/rand" "testing" @@ -73,6 +72,8 @@ func TestConsensusPayload_Setters(t *testing.T) { require.Equal(t, pl, p.GetRecoveryMessage()) } +//TODO NEO3.0: Update binary +/* func TestConsensusPayload_Hash(t *testing.T) { dataHex := "00000000d8fb8d3b143b5f98468ef701909c976505a110a01e26c5e99be9a90cff979199b6fc33000400000000008d2000184dc95de24018f9ad71f4448a2b438eaca8b4b2ab6b4524b5a69a45d920c35103f3901444320656c390ff39c0062f5e8e138ce446a40c7e4ba1af1f8247ebbdf49295933715d3a67949714ff924f8a28cec5b954c71eca3bfaf0e9d4b1f87b4e21e9ba4ae18f97de71501b5c5d07edc200bd66a46b9b28b1a371f2195c10b0af90000e24018f900000000014140c9faaee59942f58da0e5268bc199632f2a3ad0fcbee68681a4437f140b49512e8d9efc6880eb44d3490782895a5794f35eeccee2923ce0c76fa7a1890f934eac232103c089d7122b840a4935234e82e26ae5efd0c2acb627239dc9f207311337b6f2c1ac" data, err := hex.DecodeString(dataHex) @@ -82,7 +83,7 @@ func TestConsensusPayload_Hash(t *testing.T) { require.NoError(t, testserdes.DecodeBinary(data, &p)) require.Equal(t, p.Hash().String(), "45859759c8491597804f1922773947e0d37bf54484af82f80cd642f7b063aa56") } - +*/ func TestConsensusPayload_Serializable(t *testing.T) { for _, mt := range messageTypes { p := randomPayload(t, mt) diff --git a/pkg/consensus/recovery_message_test.go b/pkg/consensus/recovery_message_test.go index d6a0fdc94..67f5813af 100644 --- a/pkg/consensus/recovery_message_test.go +++ b/pkg/consensus/recovery_message_test.go @@ -1,15 +1,12 @@ package consensus import ( - "encoding/hex" - gio "io" "testing" "github.com/nspcc-dev/dbft/crypto" "github.com/nspcc-dev/dbft/payload" "github.com/nspcc-dev/neo-go/pkg/core/transaction" "github.com/nspcc-dev/neo-go/pkg/crypto/keys" - "github.com/nspcc-dev/neo-go/pkg/io" "github.com/nspcc-dev/neo-go/pkg/util" "github.com/stretchr/testify/require" ) @@ -114,6 +111,8 @@ func TestRecoveryMessage_Setters(t *testing.T) { }) } +//TODO NEO3.0: Update binary +/* func TestRecoveryMessage_DecodeFromTestnet(t *testing.T) { hexDump := "00000000924b2fa6728782b6afb94873a377c49f31573005e7f2945beb27158ec2e887300d180000010000000000" + "fd29024100000120003db64b5e8e4ab7138abe65a3be48d3a3f5d10013ab9ffee489706078714f1ea20161e7ba952fdfd5f543891b1fe053af401bc34e9e3f63c90e3c0d6675d156344b00008e4ab71300000000030000414079946c76007e4297b06b074a20dc1d1d6871c74976f244df81bd03f4158a11dd485ed50fc0cc7c6ad352addd8440c5a55d7b7449650bb200e5e58b1fb8a0390c010041403631a490b17ca4fcfe52ed2e7a4ca4c0d3fcca67e73a1ef071f385db1d37cefa7a2de6e56654788647e9142425c29449b0bbfee5c46a96c4bdc79b23c1f862fc02004140147914878c23a9624a62598cebe2c75fdce80c1e19b5c73aa511630f67d4e5a660c63daad7fcfa9bd944f258f51427cb80730b8beb3015a3c2766325bf291a8e02000000989f8fa676ed07885a46ee08af10e1fa1893ef20fbd557dc3c1a9dc498189d5fceff694dcb2085e4969d90c56433b88fd7ba1caef9363829c70419a5314ac36541404f3ee34e11c521f2e31fee439206474d36951443014354ce81b32bd1787e6a92212737f7f72bee59c403ff74292ebf78c4091081174b5921c148cedcbe7bd585000100acfc8399bda6429c64b5c09885a3e4f1a0629f59125df03be956c00f5bb77616c43e43250e96700f80c42ef3e169e9ff9f906518acf0da17c53563ba41d91ebc41409957436afd1736970d4b5e52b8d845663d6b0335a34cf78ece733c71be876cf30125e9bfea197a607ea6945cef7ef28a74676ec23d14378f7ec23964544b6710014140b634941ecab3a5dd7251f9213bfbcff2021b1e3d966e6800007ea6f0d72ec46d2c04c042800e103091d2f5d184d997a10b890b13bf06b1078a4f1822d722891a232102a7bc55fe8684e0119768d104ba30795bdcc86619e864add26156723ed185cd62ac" @@ -128,7 +127,7 @@ func TestRecoveryMessage_DecodeFromTestnet(t *testing.T) { buf.ReadB() require.Equal(t, gio.EOF, buf.Err) } - +*/ func getKeys(t *testing.T, n int) []*privateKey { privs := make([]*privateKey, 0, n) for i := 0; i < n; i++ { diff --git a/pkg/core/block/block_test.go b/pkg/core/block/block_test.go index 0aec0bf7d..15e6acd37 100644 --- a/pkg/core/block/block_test.go +++ b/pkg/core/block/block_test.go @@ -1,19 +1,16 @@ package block import ( - "encoding/hex" "testing" "github.com/nspcc-dev/neo-go/pkg/core/transaction" "github.com/nspcc-dev/neo-go/pkg/crypto/hash" - "github.com/nspcc-dev/neo-go/pkg/encoding/address" - "github.com/nspcc-dev/neo-go/pkg/internal/testserdes" "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" ) // Test blocks are blocks from mainnet with their corresponding index. - +// TODO NEO3.0: Update binary +/* func TestDecodeBlock1(t *testing.T) { data, err := getBlockData(1) require.NoError(t, err) @@ -67,7 +64,7 @@ func TestTrimmedBlock(t *testing.T) { assert.True(t, trimmedBlock.Transactions[i].Trimmed) } } - +*/ func newDumbBlock() *Block { return &Block{ Base: Base{ diff --git a/pkg/core/blockchain.go b/pkg/core/blockchain.go index 02b08f724..20ebc9f65 100644 --- a/pkg/core/blockchain.go +++ b/pkg/core/blockchain.go @@ -1340,6 +1340,10 @@ func (bc *Blockchain) verifyHeader(currHeader, prevHeader *block.Header) error { // verifyTx verifies whether a transaction is bonafide or not. func (bc *Blockchain) verifyTx(t *transaction.Transaction, block *block.Block) error { + height := bc.BlockHeight() + if t.ValidUntilBlock <= height || t.ValidUntilBlock > height+transaction.MaxValidUntilBlockIncrement { + return errors.Errorf("transaction has expired. ValidUntilBlock = %d, current height = %d", t.ValidUntilBlock, height) + } if io.GetVarSize(t) > transaction.MaxTransactionSize { return errors.Errorf("invalid transaction size = %d. It shoud be less then MaxTransactionSize = %d", io.GetVarSize(t), transaction.MaxTransactionSize) } diff --git a/pkg/core/blockchain_test.go b/pkg/core/blockchain_test.go index 4a571e438..8db37d6e0 100644 --- a/pkg/core/blockchain_test.go +++ b/pkg/core/blockchain_test.go @@ -7,7 +7,6 @@ import ( "github.com/nspcc-dev/neo-go/pkg/core/storage" "github.com/nspcc-dev/neo-go/pkg/core/transaction" "github.com/nspcc-dev/neo-go/pkg/crypto/hash" - "github.com/nspcc-dev/neo-go/pkg/io" "github.com/nspcc-dev/neo-go/pkg/util" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -98,7 +97,9 @@ func TestScriptFromWitness(t *testing.T) { func TestGetHeader(t *testing.T) { bc := newTestChain(t) - block := bc.newBlock(transaction.NewMinerTX()) + tx := transaction.NewMinerTX() + tx.ValidUntilBlock = bc.BlockHeight() + 1 + block := bc.newBlock(tx) err := bc.AddBlock(block) assert.Nil(t, err) @@ -149,6 +150,8 @@ func TestHasBlock(t *testing.T) { } } +//TODO NEO3.0:Update binary +/* func TestGetTransaction(t *testing.T) { b1 := getDecodedBlock(t, 1) block := getDecodedBlock(t, 2) @@ -174,7 +177,7 @@ func TestGetTransaction(t *testing.T) { assert.NoError(t, bc.persist()) } } - +*/ func TestGetClaimable(t *testing.T) { bc := newTestChain(t) diff --git a/pkg/core/helper_test.go b/pkg/core/helper_test.go index ed491881d..b1a69871f 100644 --- a/pkg/core/helper_test.go +++ b/pkg/core/helper_test.go @@ -96,7 +96,9 @@ func (bc *Blockchain) genBlocks(n int) ([]*block.Block, error) { lastHash := bc.topBlock.Load().(*block.Block).Hash() lastIndex := bc.topBlock.Load().(*block.Block).Index for i := 0; i < n; i++ { - blocks[i] = newBlock(bc.config, uint32(i)+lastIndex+1, lastHash, transaction.NewMinerTXWithNonce(uint32(1234+i))) + minerTx := transaction.NewMinerTXWithNonce(uint32(1234 + i)) + minerTx.ValidUntilBlock = lastIndex + uint32(i) + 1 + blocks[i] = newBlock(bc.config, uint32(i)+lastIndex+1, lastHash, minerTx) if err := bc.AddBlock(blocks[i]); err != nil { return blocks, err } @@ -167,6 +169,8 @@ func TestCreateBasicChain(t *testing.T) { const prefix = "../rpc/server/testdata/" // To make enough GAS. const numOfEmptyBlocks = 200 + // Increase in case if you need more blocks + const validUntilBlock = numOfEmptyBlocks + 1000 // To be incremented after each created transaction to keep chain constant. var testNonce uint32 = 1 @@ -177,12 +181,20 @@ func TestCreateBasicChain(t *testing.T) { return testNonce } + // Creates new miner tx with specified validUntilBlock field + nextMinerTx := func(validUntilBlock uint32) *transaction.Transaction { + minerTx := transaction.NewMinerTXWithNonce(getNextNonce()) + minerTx.ValidUntilBlock = validUntilBlock + return minerTx + } + var neoAmount = util.Fixed8FromInt64(99999000) var neoRemainder = util.Fixed8FromInt64(100000000) - neoAmount bc := newTestChain(t) // Move almost all NEO to one simple account. txMoveNeo := transaction.NewContractTX() + txMoveNeo.ValidUntilBlock = validUntilBlock txMoveNeo.Nonce = getNextNonce() // use output of issue tx from genesis block as an input @@ -231,8 +243,7 @@ func TestCreateBasicChain(t *testing.T) { InvocationScript: invoc, VerificationScript: rawScript, }} - - b := bc.newBlock(transaction.NewMinerTXWithNonce(getNextNonce()), txMoveNeo) + b := bc.newBlock(nextMinerTx(validUntilBlock), txMoveNeo) require.NoError(t, bc.AddBlock(b)) t.Logf("txMoveNeo: %s", txMoveNeo.Hash().StringLE()) @@ -252,6 +263,7 @@ func TestCreateBasicChain(t *testing.T) { // Make a NEO roundtrip (send to myself) and claim GAS. txNeoRound := transaction.NewContractTX() txNeoRound.Nonce = getNextNonce() + txNeoRound.ValidUntilBlock = validUntilBlock txNeoRound.AddInput(&transaction.Input{ PrevHash: txMoveNeo.Hash(), PrevIndex: 0, @@ -264,7 +276,7 @@ func TestCreateBasicChain(t *testing.T) { }) txNeoRound.Data = new(transaction.ContractTX) require.NoError(t, acc0.SignTx(txNeoRound)) - b = bc.newBlock(transaction.NewMinerTXWithNonce(getNextNonce()), txNeoRound) + b = bc.newBlock(nextMinerTx(validUntilBlock), txNeoRound) require.NoError(t, bc.AddBlock(b)) t.Logf("txNeoRound: %s", txNeoRound.Hash().StringLE()) @@ -275,6 +287,7 @@ func TestCreateBasicChain(t *testing.T) { }) txClaim := transaction.NewClaimTX(claim) txClaim.Nonce = getNextNonce() + txClaim.ValidUntilBlock = validUntilBlock txClaim.Data = claim neoGas, sysGas, err := bc.CalculateClaimable(neoAmount, 1, bc.BlockHeight()) require.NoError(t, err) @@ -286,7 +299,7 @@ func TestCreateBasicChain(t *testing.T) { Position: 0, }) require.NoError(t, acc0.SignTx(txClaim)) - b = bc.newBlock(transaction.NewMinerTXWithNonce(getNextNonce()), txClaim) + b = bc.newBlock(nextMinerTx(validUntilBlock), txClaim) require.NoError(t, bc.AddBlock(b)) t.Logf("txClaim: %s", txClaim.Hash().StringLE()) @@ -315,6 +328,7 @@ func TestCreateBasicChain(t *testing.T) { invFee := util.Fixed8FromFloat(100) txDeploy := transaction.NewInvocationTX(txScript, invFee) txDeploy.Nonce = getNextNonce() + txDeploy.ValidUntilBlock = validUntilBlock txDeploy.AddInput(&transaction.Input{ PrevHash: txClaim.Hash(), PrevIndex: 0, @@ -327,7 +341,7 @@ func TestCreateBasicChain(t *testing.T) { }) gasOwned -= invFee require.NoError(t, acc0.SignTx(txDeploy)) - b = bc.newBlock(transaction.NewMinerTXWithNonce(getNextNonce()), txDeploy) + b = bc.newBlock(nextMinerTx(validUntilBlock), txDeploy) require.NoError(t, bc.AddBlock(b)) t.Logf("txDeploy: %s", txDeploy.Hash().StringLE()) @@ -337,7 +351,8 @@ func TestCreateBasicChain(t *testing.T) { txInv := transaction.NewInvocationTX(script.Bytes(), 0) txInv.Nonce = getNextNonce() - b = bc.newBlock(transaction.NewMinerTXWithNonce(getNextNonce()), txInv) + txInv.ValidUntilBlock = validUntilBlock + b = bc.newBlock(nextMinerTx(validUntilBlock), txInv) require.NoError(t, bc.AddBlock(b)) t.Logf("txInv: %s", txInv.Hash().StringLE()) @@ -345,6 +360,7 @@ func TestCreateBasicChain(t *testing.T) { require.NoError(t, err) txNeo0to1 := transaction.NewContractTX() txNeo0to1.Nonce = getNextNonce() + txNeo0to1.ValidUntilBlock = validUntilBlock txNeo0to1.Data = new(transaction.ContractTX) txNeo0to1.AddInput(&transaction.Input{ PrevHash: txNeoRound.Hash(), @@ -362,7 +378,7 @@ func TestCreateBasicChain(t *testing.T) { }) require.NoError(t, acc0.SignTx(txNeo0to1)) - b = bc.newBlock(transaction.NewMinerTXWithNonce(getNextNonce()), txNeo0to1) + b = bc.newBlock(nextMinerTx(validUntilBlock), txNeo0to1) require.NoError(t, bc.AddBlock(b)) sh := hash.Hash160(avm) @@ -370,15 +386,18 @@ func TestCreateBasicChain(t *testing.T) { emit.AppCallWithOperationAndArgs(w.BinWriter, sh, "init") initTx := transaction.NewInvocationTX(w.Bytes(), 0) initTx.Nonce = getNextNonce() + initTx.ValidUntilBlock = validUntilBlock transferTx := newNEP5Transfer(sh, sh, priv0.GetScriptHash(), 1000) transferTx.Nonce = getNextNonce() + transferTx.ValidUntilBlock = validUntilBlock - b = bc.newBlock(transaction.NewMinerTXWithNonce(getNextNonce()), initTx, transferTx) + b = bc.newBlock(nextMinerTx(validUntilBlock), initTx, transferTx) require.NoError(t, bc.AddBlock(b)) transferTx = newNEP5Transfer(sh, priv0.GetScriptHash(), priv1.GetScriptHash(), 123) transferTx.Nonce = getNextNonce() - b = bc.newBlock(transaction.NewMinerTXWithNonce(getNextNonce()), transferTx) + transferTx.ValidUntilBlock = validUntilBlock + b = bc.newBlock(nextMinerTx(validUntilBlock), transferTx) require.NoError(t, bc.AddBlock(b)) if saveChain { @@ -406,6 +425,7 @@ func TestCreateBasicChain(t *testing.T) { // Make a NEO roundtrip (send to myself) and claim GAS. txNeoRound = transaction.NewContractTX() txNeoRound.Nonce = getNextNonce() + txNeoRound.ValidUntilBlock = validUntilBlock txNeoRound.AddInput(&transaction.Input{ PrevHash: txNeo0to1.Hash(), PrevIndex: 1, @@ -425,7 +445,7 @@ func TestCreateBasicChain(t *testing.T) { // Blocks for `submitblock` test. If you are planning to modify test chain from `testblocks.acc`, // please, update params value of `empty block` and `positive` tests. var blocks []*block.Block - blocks = append(blocks, bc.newBlock(), bc.newBlock(transaction.NewMinerTXWithNonce(getNextNonce()))) + blocks = append(blocks, bc.newBlock(), bc.newBlock(nextMinerTx(validUntilBlock))) for i, b := range blocks { data, err := testserdes.EncodeBinary(b) require.NoError(t, err) diff --git a/pkg/core/transaction/miner_test.go b/pkg/core/transaction/miner_test.go index 6e4d0fc3a..b15814952 100644 --- a/pkg/core/transaction/miner_test.go +++ b/pkg/core/transaction/miner_test.go @@ -1,13 +1,7 @@ package transaction -import ( - "encoding/hex" - "testing" - - "github.com/nspcc-dev/neo-go/pkg/internal/testserdes" - "github.com/stretchr/testify/assert" -) - +// TODO NEO3.0: Update binary +/* func TestEncodeDecodeMiner(t *testing.T) { // transaction from mainnet a1f219dc6be4c35eca172e65e02d4591045220221b1543f1a4b67b9e9442c264 rawtx := "0000fcd30e22000001e72d286979ee6cb1b7e65dfddfb2e384100b8d148e7758de42e4168b71792c60c8000000000000001f72e68b4e39602912106d53b229378a082784b200" @@ -24,3 +18,4 @@ func TestEncodeDecodeMiner(t *testing.T) { assert.NoError(t, err) assert.Equal(t, rawtx, hex.EncodeToString(data)) } +*/ diff --git a/pkg/core/transaction/transaction.go b/pkg/core/transaction/transaction.go index 49dc4e292..1bb333a5c 100644 --- a/pkg/core/transaction/transaction.go +++ b/pkg/core/transaction/transaction.go @@ -17,6 +17,9 @@ const ( // MaxTransactionSize is the upper limit size in bytes that a transaction can reach. It is // set to be 102400. MaxTransactionSize = 102400 + // MaxValidUntilBlockIncrement is the upper increment size of blockhain height in blocs after + // exceeding that a transaction should fail validation. It is set to be 2102400. + MaxValidUntilBlockIncrement = 2102400 ) // Transaction is a process recorded in the NEO blockchain. @@ -30,6 +33,10 @@ type Transaction struct { // Random number to avoid hash collision. Nonce uint32 + // Maximum blockchain height exceeding which + // transaction should fail verification. + ValidUntilBlock uint32 + // Data specific to the type of the transaction. // This is always a pointer to a Transaction. Data TXer @@ -111,6 +118,7 @@ func (t *Transaction) DecodeBinary(br *io.BinReader) { t.Type = TXType(br.ReadB()) t.Version = uint8(br.ReadB()) t.Nonce = br.ReadU32LE() + t.ValidUntilBlock = br.ReadU32LE() t.decodeData(br) br.ReadArray(&t.Attributes) @@ -182,6 +190,7 @@ func (t *Transaction) encodeHashableFields(bw *io.BinWriter) { bw.WriteB(byte(t.Type)) bw.WriteB(byte(t.Version)) bw.WriteU32LE(t.Nonce) + bw.WriteU32LE(t.ValidUntilBlock) // Underlying TXer. if !noData { @@ -257,15 +266,16 @@ func NewTransactionFromBytes(b []byte) (*Transaction, error) { // transactionJSON is a wrapper for Transaction and // used for correct marhalling of transaction.Data type transactionJSON struct { - TxID util.Uint256 `json:"txid"` - Size int `json:"size"` - Type TXType `json:"type"` - Version uint8 `json:"version"` - Nonce uint32 `json:"nonce"` - Attributes []Attribute `json:"attributes"` - Inputs []Input `json:"vin"` - Outputs []Output `json:"vout"` - Scripts []Witness `json:"scripts"` + TxID util.Uint256 `json:"txid"` + Size int `json:"size"` + Type TXType `json:"type"` + Version uint8 `json:"version"` + Nonce uint32 `json:"nonce"` + ValidUntilBlock uint32 `json:"valid_until_block"` + Attributes []Attribute `json:"attributes"` + Inputs []Input `json:"vin"` + Outputs []Output `json:"vout"` + Scripts []Witness `json:"scripts"` Claims []Input `json:"claims,omitempty"` PublicKey *keys.PublicKey `json:"pubkey,omitempty"` @@ -279,15 +289,16 @@ type transactionJSON struct { // MarshalJSON implements json.Marshaler interface. func (t *Transaction) MarshalJSON() ([]byte, error) { tx := transactionJSON{ - TxID: t.Hash(), - Size: io.GetVarSize(t), - Type: t.Type, - Version: t.Version, - Nonce: t.Nonce, - Attributes: t.Attributes, - Inputs: t.Inputs, - Outputs: t.Outputs, - Scripts: t.Scripts, + TxID: t.Hash(), + Size: io.GetVarSize(t), + Type: t.Type, + Version: t.Version, + Nonce: t.Nonce, + ValidUntilBlock: t.ValidUntilBlock, + Attributes: t.Attributes, + Inputs: t.Inputs, + Outputs: t.Outputs, + Scripts: t.Scripts, } switch t.Type { case ClaimType: @@ -338,6 +349,7 @@ func (t *Transaction) UnmarshalJSON(data []byte) error { t.Type = tx.Type t.Version = tx.Version t.Nonce = tx.Nonce + t.ValidUntilBlock = tx.ValidUntilBlock t.Attributes = tx.Attributes t.Inputs = tx.Inputs t.Outputs = tx.Outputs diff --git a/pkg/core/util_test.go b/pkg/core/util_test.go index 629c6f1a6..22ba5d085 100644 --- a/pkg/core/util_test.go +++ b/pkg/core/util_test.go @@ -20,7 +20,7 @@ func TestGenesisBlockMainNet(t *testing.T) { // have been changed. Consequently, hash of the genesis block has been changed. // Update expected genesis block hash for better times. // Old hash is "d42561e3d30e15be6400b6df2f328e02d2bf6354c41dce433bc57687c82144bf" - expect := "8c5e44474b2b942286071254fd4bffddd3febd0511b101e566331b5f8f041902" + expect := "cf98b48f81ce3162cdd0883bb0c4cbf3abc105623ba7a61133a776c1e33a2466" assert.Equal(t, expect, block.Hash().StringLE()) } @@ -47,7 +47,7 @@ func TestUtilityTokenTX(t *testing.T) { //TODO: After we added Nonce field to transaction.Transaction, UtilityTockenTx hash // has been changed. Update it for better times. // Old hash is "602c79718b16e442de58778e148d0b1084e3b2dffd5de6b7b16cee7969282de7" - expect := "057ea06225860f0f7e69cca1e0052652918629929591b8138a516431be144ba8" + expect := "8dd7d330dd7fc103836409bdcba826d15d88119c7f843357266b253aede72dfb" assert.Equal(t, expect, UtilityTokenID().StringLE()) } @@ -55,6 +55,6 @@ func TestGoverningTokenTX(t *testing.T) { //TODO: After we added Nonce field to transaction.Transaction, GoveringTockenTx hash // has been changed. Update it for better times. // Old hash is "c56f33fc6ecfcd0c225c4ab356fee59390af8560be0e930faebe74a6daff7c9b" - expect := "cd3a3b5654465238c3a4ac30eeb1bfd1171378d59b27f7d2e6893ce9d6150825" + expect := "0589624521f631b389197e1a69b1b92db0a45cc70f45c3409dfecc439e99bfa9" assert.Equal(t, expect, GoverningTokenID().StringLE()) } diff --git a/pkg/rpc/client/client.go b/pkg/rpc/client/client.go index a18f42ef0..3a5c2820f 100644 --- a/pkg/rpc/client/client.go +++ b/pkg/rpc/client/client.go @@ -24,6 +24,8 @@ const ( defaultDialTimeout = 4 * time.Second defaultRequestTimeout = 4 * time.Second defaultClientVersion = "2.0" + // number of blocks after which cache is expired + cacheTimeout = 100 ) // Client represents the middleman for executing JSON RPC calls @@ -40,6 +42,7 @@ type Client struct { wif *keys.WIF balancerMu *sync.Mutex balancer request.BalanceGetter + cache cache } // Options defines options for the RPC client. @@ -57,6 +60,18 @@ type Options struct { Version string } +// cache stores cache values for the RPC client methods +type cache struct { + calculateValidUntilBlock calculateValidUntilBlockCache +} + +// calculateValidUntilBlockCache stores cached number of validators and +// cache expiration value in blocks +type calculateValidUntilBlockCache struct { + validatorsCount uint32 + expiresAt uint32 +} + // New returns a new Client ready to use. func New(ctx context.Context, endpoint string, opts Options) (*Client, error) { url, err := url.Parse(endpoint) @@ -158,7 +173,7 @@ func (c *Client) SetClient(cli *http.Client) { // CalculateInputs creates input transactions for the specified amount of given // asset belonging to specified address. This implementation uses GetUnspents -// JSON-RPC call internally, so make sure your RPC server suppors that. +// JSON-RPC call internally, so make sure your RPC server supports that. func (c *Client) CalculateInputs(address string, asset util.Uint256, cost util.Fixed8) ([]transaction.Input, util.Fixed8, error) { var utxos state.UnspentBalances diff --git a/pkg/rpc/client/rpc.go b/pkg/rpc/client/rpc.go index fa9d3e9c9..386a4af4b 100644 --- a/pkg/rpc/client/rpc.go +++ b/pkg/rpc/client/rpc.go @@ -490,6 +490,13 @@ func (c *Client) TransferAsset(asset util.Uint256, address string, amount util.F if rawTx, err = request.CreateRawContractTransaction(txParams); err != nil { return resp, errors.Wrap(err, "failed to create raw transaction") } + + validUntilBlock, err := c.CalculateValidUntilBlock() + if err != nil { + return resp, errors.Wrap(err, "failed to add validUntilBlock to raw transaction") + } + rawTx.ValidUntilBlock = validUntilBlock + if err = c.SendRawTransaction(rawTx); err != nil { return resp, errors.Wrap(err, "failed to send raw transaction") } @@ -504,6 +511,12 @@ func (c *Client) SignAndPushInvocationTx(script []byte, acc *wallet.Account, sys var err error tx := transaction.NewInvocationTX(script, sysfee) + validUntilBlock, err := c.CalculateValidUntilBlock() + if err != nil { + return txHash, errors.Wrap(err, "failed to add validUntilBlock to transaction") + } + tx.ValidUntilBlock = validUntilBlock + gas := sysfee + netfee if gas > 0 { @@ -545,3 +558,33 @@ func (c *Client) ValidateAddress(address string) error { } return nil } + +// CalculateValidUntilBlock calculates ValidUntilBlock field for tx as +// current blockchain height + number of validators. Number of validators +// is the length of blockchain validators list got from GetValidators() +// method. Validators count is being cached and updated every 100 blocks. +func (c *Client) CalculateValidUntilBlock() (uint32, error) { + var ( + result uint32 + validatorsCount uint32 + ) + blockCount, err := c.GetBlockCount() + if err != nil { + return result, errors.Wrapf(err, "cannot get block count") + } + + if c.cache.calculateValidUntilBlock.expiresAt > blockCount { + validatorsCount = c.cache.calculateValidUntilBlock.validatorsCount + } else { + validators, err := c.GetValidators() + if err != nil { + return result, errors.Wrapf(err, "cannot get validators") + } + validatorsCount = uint32(len(validators)) + c.cache.calculateValidUntilBlock = calculateValidUntilBlockCache{ + validatorsCount: validatorsCount, + expiresAt: blockCount + cacheTimeout, + } + } + return blockCount + validatorsCount, nil +} diff --git a/pkg/rpc/client/rpc_test.go b/pkg/rpc/client/rpc_test.go index 339a6ed1d..2d69e426c 100644 --- a/pkg/rpc/client/rpc_test.go +++ b/pkg/rpc/client/rpc_test.go @@ -8,6 +8,8 @@ import ( "net/http/httptest" "testing" + "github.com/nspcc-dev/neo-go/pkg/rpc/request" + "github.com/nspcc-dev/neo-go/pkg/core" "github.com/nspcc-dev/neo-go/pkg/core/block" "github.com/nspcc-dev/neo-go/pkg/core/transaction" @@ -37,7 +39,7 @@ var rpcClientTestCases = map[string][]rpcClientTestCase{ invoke: func(c *Client) (interface{}, error) { return c.GetAccountState("") }, - serverResponse: `{"jsonrpc":"2.0","id": 1,"result":{"version":0,"script_hash":"0x1179716da2e9523d153a35fb3ad10c561b1e5b1a","frozen":false,"votes":[],"balances":[{"asset":"0xcd3a3b5654465238c3a4ac30eeb1bfd1171378d59b27f7d2e6893ce9d6150825","value":"94"}]}}`, + serverResponse: `{"jsonrpc":"2.0","id": 1,"result":{"version":0,"script_hash":"0x1179716da2e9523d153a35fb3ad10c561b1e5b1a","frozen":false,"votes":[],"balances":[{"asset":"0x0589624521f631b389197e1a69b1b92db0a45cc70f45c3409dfecc439e99bfa9","value":"94"}]}}`, result: func(c *Client) interface{} { scriptHash, err := util.Uint160DecodeStringLE("1179716da2e9523d153a35fb3ad10c561b1e5b1a") if err != nil { @@ -96,7 +98,7 @@ var rpcClientTestCases = map[string][]rpcClientTestCase{ invoke: func(c *Client) (interface{}, error) { return c.GetAssetState(util.Uint256{}) }, - serverResponse: `{"id":1,"jsonrpc":"2.0","result":{"id":"0xcd3a3b5654465238c3a4ac30eeb1bfd1171378d59b27f7d2e6893ce9d6150825","type":0,"name":"NEO","amount":"100000000","available":"100000000","precision":0,"owner":"00","admin":"Abf2qMs1pzQb8kYk9RuxtUb9jtRKJVuBJt","issuer":"AFmseVrdL9f9oyCzZefL9tG6UbvhPbdYzM","expiration":4000000,"is_frozen":false}}`, + serverResponse: `{"id":1,"jsonrpc":"2.0","result":{"id":"0x0589624521f631b389197e1a69b1b92db0a45cc70f45c3409dfecc439e99bfa9","type":0,"name":"NEO","amount":"100000000","available":"100000000","precision":0,"owner":"00","admin":"Abf2qMs1pzQb8kYk9RuxtUb9jtRKJVuBJt","issuer":"AFmseVrdL9f9oyCzZefL9tG6UbvhPbdYzM","expiration":4000000,"is_frozen":false}}`, result: func(c *Client) interface{} { return &result.AssetState{ ID: core.GoverningTokenID(), @@ -134,45 +136,45 @@ var rpcClientTestCases = map[string][]rpcClientTestCase{ { name: "byIndex_positive", invoke: func(c *Client) (interface{}, error) { - return c.GetBlockByIndex(1) + return c.GetBlockByIndex(5) }, - serverResponse: `{"id":1,"jsonrpc":"2.0","result":"00000000999086db552ba8f84734bddca55b25a8d3d8c5f866f941209169c38d35376e99b29ffa96224227f5e033c9a291bceef2724429d596c3a6944cafd6995fdb6dcbe013dd5b010000004ded49fea284b451be48d3a3f5d10013ab9ffee489706078714f1ea201c340356a91d94e398170e47447d6a0f60aa5470e209782a5452403115a49166db3e1c4a3898122db19f779c30f8ccd0b7d401acdf71eda340655e4ae5237a64961bf4034dd47955e5a71627dafc39dd92999140e9eaeec6b11dbb2b313efa3f1093ed915b4455e199c69ec53778f94ffc236b92f8b97fff97a1f6bbb3770c0c0b3844a40fbe743bd5c90b2f5255e0b073281d7aeb2fb516572f36bec8446bcc37ac755cbf10d08b16c95644db1b2dddc2df5daa377880b20198fc7b967ac6e76474b22df8b532102103a7f7dd016558597f7960d27c516a4394fd968b9e65155eb4b013e4040406e2102a7bc55fe8684e0119768d104ba30795bdcc86619e864add26156723ed185cd622102b3622bf4017bdfe317c58aed5f4c753f206b7db896046fa7d774bbc4bf7f8dc22103d90c07df63e690ce77912e10ab51acc944b66860237b608c4f8f8309e71ee69954ae0100004ded49fe00000000"}`, + serverResponse: `{"id":1,"jsonrpc":"2.0","result":"00000000a78c4548ad5fd899f4980cffcc8610f4dc22037de3f1fd374cc4384e1eb24e85f0bd34849ad1bda48acd6b9c9401654f9e6499f95dab85923de66c3b1242d59c858e955e050000005704000000000000be48d3a3f5d10013ab9ffee489706078714f1ea201fd040140445e8de1ba402cab0bffedc32840b3587c8f6b272c02ea2b4a609419fbcb85a3cf5cd183ea7d28788eb19a12265be1d2f43f7986de66c8d8585d66825a0701fc40d935dfb83310d3433a7afc0bbb15f4c0686a624734cee6f6b98d5d95e660401c5b35c7cfd802fa82759aab288373ad894d82056d29109e6142d8c1397f60706f4076e9fd7bef3b9a8ce12904414cc55293161bcb536a4939200dd3c586c4d60ded565780d307598b8dcf4eebb64f53cc9fc0c381d47e58b7cec1b9392097a2b3ec407b03a25d83d429810b7a929f48b8125d3bfff5982f876c0dbd1d9dbbf08534d3235a4709c7f779449ed865ca1d2e29729c0210174782869a09c2b821bd15fda18b532102103a7f7dd016558597f7960d27c516a4394fd968b9e65155eb4b013e4040406e2102a7bc55fe8684e0119768d104ba30795bdcc86619e864add26156723ed185cd622102b3622bf4017bdfe317c58aed5f4c753f206b7db896046fa7d774bbc4bf7f8dc22103d90c07df63e690ce77912e10ab51acc944b66860237b608c4f8f8309e71ee69954ae010000d50400000500000000000000"}`, result: func(c *Client) interface{} { return &block.Block{} }, check: func(t *testing.T, c *Client, result interface{}) { res, ok := result.(*block.Block) require.True(t, ok) assert.Equal(t, uint32(0), res.Version) - assert.Equal(t, "e93d17a52967f9e69314385482bf86f85260e811b46bf4d4b261a7f4135a623c", res.Hash().StringLE()) - assert.Equal(t, "996e37358dc369912041f966f8c5d8d3a8255ba5dcbd3447f8a82b55db869099", res.PrevHash.StringLE()) - assert.Equal(t, "cb6ddb5f99d6af4c94a6c396d5294472f2eebc91a2c933e0f527422296fa9fb2", res.MerkleRoot.StringLE()) + assert.Equal(t, "a928e6e394bbc8ebb02b88fa14efb2860c9de376b4809ba078e7e47ca9a77af9", res.Hash().StringLE()) + assert.Equal(t, "854eb21e4e38c44c37fdf1e37d0322dcf41086ccff0c98f499d85fad48458ca7", res.PrevHash.StringLE()) + assert.Equal(t, "9cd542123b6ce63d9285ab5df999649e4f6501949c6bcd8aa4bdd19a8434bdf0", res.MerkleRoot.StringLE()) assert.Equal(t, 1, len(res.Transactions)) - assert.Equal(t, "cb6ddb5f99d6af4c94a6c396d5294472f2eebc91a2c933e0f527422296fa9fb2", res.Transactions[0].Hash().StringLE()) + assert.Equal(t, "9cd542123b6ce63d9285ab5df999649e4f6501949c6bcd8aa4bdd19a8434bdf0", res.Transactions[0].Hash().StringLE()) }, }, { name: "byIndex_verbose_positive", invoke: func(c *Client) (i interface{}, err error) { - return c.GetBlockByIndexVerbose(1) + return c.GetBlockByIndexVerbose(5) }, - serverResponse: `{"id":1,"jsonrpc":"2.0","result":{"hash":"0xe93d17a52967f9e69314385482bf86f85260e811b46bf4d4b261a7f4135a623c","size":452,"version":0,"nextblockhash":"0xcc37d5bc460e72c9423015cb8d579c13e7b03b93bfaa1a23cf4fa777988e035f","previousblockhash":"0x996e37358dc369912041f966f8c5d8d3a8255ba5dcbd3447f8a82b55db869099","merkleroot":"0xcb6ddb5f99d6af4c94a6c396d5294472f2eebc91a2c933e0f527422296fa9fb2","time":1541215200,"index":1,"nonce":"51b484a2fe49ed4d","nextconsensus":"AZ81H31DMWzbSnFDLFkzh9vHwaDLayV7fU","confirmations":10534,"script":{"invocation":"40356a91d94e398170e47447d6a0f60aa5470e209782a5452403115a49166db3e1c4a3898122db19f779c30f8ccd0b7d401acdf71eda340655e4ae5237a64961bf4034dd47955e5a71627dafc39dd92999140e9eaeec6b11dbb2b313efa3f1093ed915b4455e199c69ec53778f94ffc236b92f8b97fff97a1f6bbb3770c0c0b3844a40fbe743bd5c90b2f5255e0b073281d7aeb2fb516572f36bec8446bcc37ac755cbf10d08b16c95644db1b2dddc2df5daa377880b20198fc7b967ac6e76474b22df","verification":"532102103a7f7dd016558597f7960d27c516a4394fd968b9e65155eb4b013e4040406e2102a7bc55fe8684e0119768d104ba30795bdcc86619e864add26156723ed185cd622102b3622bf4017bdfe317c58aed5f4c753f206b7db896046fa7d774bbc4bf7f8dc22103d90c07df63e690ce77912e10ab51acc944b66860237b608c4f8f8309e71ee69954ae"},"tx":[{"txid":"0xcb6ddb5f99d6af4c94a6c396d5294472f2eebc91a2c933e0f527422296fa9fb2","size":10,"type":"MinerTransaction","version":0,"attributes":[],"vin":[],"vout":[],"scripts":[],"sys_fee":"0","net_fee":"0","nonce":4266257741}]}}`, + serverResponse: `{"id":1,"jsonrpc":"2.0","result":{"hash":"0xa928e6e394bbc8ebb02b88fa14efb2860c9de376b4809ba078e7e47ca9a77af9","size":523,"version":0,"nextblockhash":"0x5ff4068d996cbefb6fb6e36f6c8085a79f7ab28cc3149b6f49a55cf97fa4b513","previousblockhash":"0x854eb21e4e38c44c37fdf1e37d0322dcf41086ccff0c98f499d85fad48458ca7","merkleroot":"0x9cd542123b6ce63d9285ab5df999649e4f6501949c6bcd8aa4bdd19a8434bdf0","time":1586859653,"index":5,"nonce":"0000000000000457","nextconsensus":"AZ81H31DMWzbSnFDLFkzh9vHwaDLayV7fU","confirmations":203,"script":{"invocation":"40445e8de1ba402cab0bffedc32840b3587c8f6b272c02ea2b4a609419fbcb85a3cf5cd183ea7d28788eb19a12265be1d2f43f7986de66c8d8585d66825a0701fc40d935dfb83310d3433a7afc0bbb15f4c0686a624734cee6f6b98d5d95e660401c5b35c7cfd802fa82759aab288373ad894d82056d29109e6142d8c1397f60706f4076e9fd7bef3b9a8ce12904414cc55293161bcb536a4939200dd3c586c4d60ded565780d307598b8dcf4eebb64f53cc9fc0c381d47e58b7cec1b9392097a2b3ec407b03a25d83d429810b7a929f48b8125d3bfff5982f876c0dbd1d9dbbf08534d3235a4709c7f779449ed865ca1d2e29729c0210174782869a09c2b821bd15fda1","verification":"532102103a7f7dd016558597f7960d27c516a4394fd968b9e65155eb4b013e4040406e2102a7bc55fe8684e0119768d104ba30795bdcc86619e864add26156723ed185cd622102b3622bf4017bdfe317c58aed5f4c753f206b7db896046fa7d774bbc4bf7f8dc22103d90c07df63e690ce77912e10ab51acc944b66860237b608c4f8f8309e71ee69954ae"},"tx":[{"sys_fee":"0","net_fee":"0","txid":"0x9cd542123b6ce63d9285ab5df999649e4f6501949c6bcd8aa4bdd19a8434bdf0","size":14,"type":"MinerTransaction","version":0,"nonce":1237,"valid_until_block":5,"attributes":[],"vin":[],"vout":[],"scripts":[]}]}}`, result: func(c *Client) interface{} { - hash, err := util.Uint256DecodeStringLE("e93d17a52967f9e69314385482bf86f85260e811b46bf4d4b261a7f4135a623c") + hash, err := util.Uint256DecodeStringLE("a928e6e394bbc8ebb02b88fa14efb2860c9de376b4809ba078e7e47ca9a77af9") if err != nil { panic(err) } - nextBlockHash, err := util.Uint256DecodeStringLE("cc37d5bc460e72c9423015cb8d579c13e7b03b93bfaa1a23cf4fa777988e035f") + nextBlockHash, err := util.Uint256DecodeStringLE("5ff4068d996cbefb6fb6e36f6c8085a79f7ab28cc3149b6f49a55cf97fa4b513") if err != nil { panic(err) } - prevBlockHash, err := util.Uint256DecodeStringLE("996e37358dc369912041f966f8c5d8d3a8255ba5dcbd3447f8a82b55db869099") + prevBlockHash, err := util.Uint256DecodeStringLE("854eb21e4e38c44c37fdf1e37d0322dcf41086ccff0c98f499d85fad48458ca7") if err != nil { panic(err) } - merkleRoot, err := util.Uint256DecodeStringLE("cb6ddb5f99d6af4c94a6c396d5294472f2eebc91a2c933e0f527422296fa9fb2") + merkleRoot, err := util.Uint256DecodeStringLE("9cd542123b6ce63d9285ab5df999649e4f6501949c6bcd8aa4bdd19a8434bdf0") if err != nil { panic(err) } - invScript, err := hex.DecodeString("40356a91d94e398170e47447d6a0f60aa5470e209782a5452403115a49166db3e1c4a3898122db19f779c30f8ccd0b7d401acdf71eda340655e4ae5237a64961bf4034dd47955e5a71627dafc39dd92999140e9eaeec6b11dbb2b313efa3f1093ed915b4455e199c69ec53778f94ffc236b92f8b97fff97a1f6bbb3770c0c0b3844a40fbe743bd5c90b2f5255e0b073281d7aeb2fb516572f36bec8446bcc37ac755cbf10d08b16c95644db1b2dddc2df5daa377880b20198fc7b967ac6e76474b22df") + invScript, err := hex.DecodeString("40445e8de1ba402cab0bffedc32840b3587c8f6b272c02ea2b4a609419fbcb85a3cf5cd183ea7d28788eb19a12265be1d2f43f7986de66c8d8585d66825a0701fc40d935dfb83310d3433a7afc0bbb15f4c0686a624734cee6f6b98d5d95e660401c5b35c7cfd802fa82759aab288373ad894d82056d29109e6142d8c1397f60706f4076e9fd7bef3b9a8ce12904414cc55293161bcb536a4939200dd3c586c4d60ded565780d307598b8dcf4eebb64f53cc9fc0c381d47e58b7cec1b9392097a2b3ec407b03a25d83d429810b7a929f48b8125d3bfff5982f876c0dbd1d9dbbf08534d3235a4709c7f779449ed865ca1d2e29729c0210174782869a09c2b821bd15fda1") if err != nil { panic(err) } @@ -180,21 +182,22 @@ var rpcClientTestCases = map[string][]rpcClientTestCase{ if err != nil { panic(err) } - tx := transaction.NewMinerTXWithNonce(4266257741) + tx := transaction.NewMinerTXWithNonce(1237) + tx.ValidUntilBlock = 5 // Update hashes for correct result comparison. _ = tx.Hash() return &result.Block{ Hash: hash, - Size: 452, + Size: 523, Version: 0, NextBlockHash: &nextBlockHash, PreviousBlockHash: prevBlockHash, MerkleRoot: merkleRoot, - Time: 1541215200, - Index: 1, - Nonce: "51b484a2fe49ed4d", + Time: 1586859653, + Index: 5, + Nonce: "0000000000000457", NextConsensus: "AZ81H31DMWzbSnFDLFkzh9vHwaDLayV7fU", - Confirmations: 10534, + Confirmations: 203, Script: transaction.Witness{ InvocationScript: invScript, VerificationScript: verifScript, @@ -212,53 +215,53 @@ var rpcClientTestCases = map[string][]rpcClientTestCase{ { name: "byHash_positive", invoke: func(c *Client) (interface{}, error) { - hash, err := util.Uint256DecodeStringLE("e93d17a52967f9e69314385482bf86f85260e811b46bf4d4b261a7f4135a623c") + hash, err := util.Uint256DecodeStringLE("f97aa7a97ce4e778a09b80b476e39d0c86b2ef14fa882bb0ebc8bb94e3e628a9") if err != nil { panic(err) } return c.GetBlockByHash(hash) }, - serverResponse: `{"id":1,"jsonrpc":"2.0","result":"00000000999086db552ba8f84734bddca55b25a8d3d8c5f866f941209169c38d35376e99b29ffa96224227f5e033c9a291bceef2724429d596c3a6944cafd6995fdb6dcbe013dd5b010000004ded49fea284b451be48d3a3f5d10013ab9ffee489706078714f1ea201c340356a91d94e398170e47447d6a0f60aa5470e209782a5452403115a49166db3e1c4a3898122db19f779c30f8ccd0b7d401acdf71eda340655e4ae5237a64961bf4034dd47955e5a71627dafc39dd92999140e9eaeec6b11dbb2b313efa3f1093ed915b4455e199c69ec53778f94ffc236b92f8b97fff97a1f6bbb3770c0c0b3844a40fbe743bd5c90b2f5255e0b073281d7aeb2fb516572f36bec8446bcc37ac755cbf10d08b16c95644db1b2dddc2df5daa377880b20198fc7b967ac6e76474b22df8b532102103a7f7dd016558597f7960d27c516a4394fd968b9e65155eb4b013e4040406e2102a7bc55fe8684e0119768d104ba30795bdcc86619e864add26156723ed185cd622102b3622bf4017bdfe317c58aed5f4c753f206b7db896046fa7d774bbc4bf7f8dc22103d90c07df63e690ce77912e10ab51acc944b66860237b608c4f8f8309e71ee69954ae0100004ded49fe00000000"}`, + serverResponse: `{"id":1,"jsonrpc":"2.0","result":"00000000a78c4548ad5fd899f4980cffcc8610f4dc22037de3f1fd374cc4384e1eb24e85f0bd34849ad1bda48acd6b9c9401654f9e6499f95dab85923de66c3b1242d59c858e955e050000005704000000000000be48d3a3f5d10013ab9ffee489706078714f1ea201fd040140445e8de1ba402cab0bffedc32840b3587c8f6b272c02ea2b4a609419fbcb85a3cf5cd183ea7d28788eb19a12265be1d2f43f7986de66c8d8585d66825a0701fc40d935dfb83310d3433a7afc0bbb15f4c0686a624734cee6f6b98d5d95e660401c5b35c7cfd802fa82759aab288373ad894d82056d29109e6142d8c1397f60706f4076e9fd7bef3b9a8ce12904414cc55293161bcb536a4939200dd3c586c4d60ded565780d307598b8dcf4eebb64f53cc9fc0c381d47e58b7cec1b9392097a2b3ec407b03a25d83d429810b7a929f48b8125d3bfff5982f876c0dbd1d9dbbf08534d3235a4709c7f779449ed865ca1d2e29729c0210174782869a09c2b821bd15fda18b532102103a7f7dd016558597f7960d27c516a4394fd968b9e65155eb4b013e4040406e2102a7bc55fe8684e0119768d104ba30795bdcc86619e864add26156723ed185cd622102b3622bf4017bdfe317c58aed5f4c753f206b7db896046fa7d774bbc4bf7f8dc22103d90c07df63e690ce77912e10ab51acc944b66860237b608c4f8f8309e71ee69954ae010000d50400000500000000000000"}`, result: func(c *Client) interface{} { return &block.Block{} }, check: func(t *testing.T, c *Client, result interface{}) { res, ok := result.(*block.Block) require.True(t, ok) assert.Equal(t, uint32(0), res.Version) - assert.Equal(t, "e93d17a52967f9e69314385482bf86f85260e811b46bf4d4b261a7f4135a623c", res.Hash().StringLE()) - assert.Equal(t, "996e37358dc369912041f966f8c5d8d3a8255ba5dcbd3447f8a82b55db869099", res.PrevHash.StringLE()) - assert.Equal(t, "cb6ddb5f99d6af4c94a6c396d5294472f2eebc91a2c933e0f527422296fa9fb2", res.MerkleRoot.StringLE()) + assert.Equal(t, "a928e6e394bbc8ebb02b88fa14efb2860c9de376b4809ba078e7e47ca9a77af9", res.Hash().StringLE()) + assert.Equal(t, "854eb21e4e38c44c37fdf1e37d0322dcf41086ccff0c98f499d85fad48458ca7", res.PrevHash.StringLE()) + assert.Equal(t, "9cd542123b6ce63d9285ab5df999649e4f6501949c6bcd8aa4bdd19a8434bdf0", res.MerkleRoot.StringLE()) assert.Equal(t, 1, len(res.Transactions)) - assert.Equal(t, "cb6ddb5f99d6af4c94a6c396d5294472f2eebc91a2c933e0f527422296fa9fb2", res.Transactions[0].Hash().StringLE()) + assert.Equal(t, "9cd542123b6ce63d9285ab5df999649e4f6501949c6bcd8aa4bdd19a8434bdf0", res.Transactions[0].Hash().StringLE()) }, }, { name: "byHash_verbose_positive", invoke: func(c *Client) (i interface{}, err error) { - hash, err := util.Uint256DecodeStringLE("e93d17a52967f9e69314385482bf86f85260e811b46bf4d4b261a7f4135a623c") + hash, err := util.Uint256DecodeStringLE("f97aa7a97ce4e778a09b80b476e39d0c86b2ef14fa882bb0ebc8bb94e3e628a9") if err != nil { panic(err) } return c.GetBlockByHashVerbose(hash) }, - serverResponse: `{"id":1,"jsonrpc":"2.0","result":{"hash":"0xe93d17a52967f9e69314385482bf86f85260e811b46bf4d4b261a7f4135a623c","size":452,"version":0,"nextblockhash":"0xcc37d5bc460e72c9423015cb8d579c13e7b03b93bfaa1a23cf4fa777988e035f","previousblockhash":"0x996e37358dc369912041f966f8c5d8d3a8255ba5dcbd3447f8a82b55db869099","merkleroot":"0xcb6ddb5f99d6af4c94a6c396d5294472f2eebc91a2c933e0f527422296fa9fb2","time":1541215200,"index":1,"nonce":"51b484a2fe49ed4d","nextconsensus":"AZ81H31DMWzbSnFDLFkzh9vHwaDLayV7fU","confirmations":10534,"script":{"invocation":"40356a91d94e398170e47447d6a0f60aa5470e209782a5452403115a49166db3e1c4a3898122db19f779c30f8ccd0b7d401acdf71eda340655e4ae5237a64961bf4034dd47955e5a71627dafc39dd92999140e9eaeec6b11dbb2b313efa3f1093ed915b4455e199c69ec53778f94ffc236b92f8b97fff97a1f6bbb3770c0c0b3844a40fbe743bd5c90b2f5255e0b073281d7aeb2fb516572f36bec8446bcc37ac755cbf10d08b16c95644db1b2dddc2df5daa377880b20198fc7b967ac6e76474b22df","verification":"532102103a7f7dd016558597f7960d27c516a4394fd968b9e65155eb4b013e4040406e2102a7bc55fe8684e0119768d104ba30795bdcc86619e864add26156723ed185cd622102b3622bf4017bdfe317c58aed5f4c753f206b7db896046fa7d774bbc4bf7f8dc22103d90c07df63e690ce77912e10ab51acc944b66860237b608c4f8f8309e71ee69954ae"},"tx":[{"txid":"0xcb6ddb5f99d6af4c94a6c396d5294472f2eebc91a2c933e0f527422296fa9fb2","size":10,"type":"MinerTransaction","version":0,"attributes":[],"vin":[],"vout":[],"scripts":[],"sys_fee":"0","net_fee":"0","nonce":4266257741}]}}`, + serverResponse: `{"id":1,"jsonrpc":"2.0","result":{"hash":"0xa928e6e394bbc8ebb02b88fa14efb2860c9de376b4809ba078e7e47ca9a77af9","size":523,"version":0,"nextblockhash":"0x5ff4068d996cbefb6fb6e36f6c8085a79f7ab28cc3149b6f49a55cf97fa4b513","previousblockhash":"0x854eb21e4e38c44c37fdf1e37d0322dcf41086ccff0c98f499d85fad48458ca7","merkleroot":"0x9cd542123b6ce63d9285ab5df999649e4f6501949c6bcd8aa4bdd19a8434bdf0","time":1586859653,"index":5,"nonce":"0000000000000457","nextconsensus":"AZ81H31DMWzbSnFDLFkzh9vHwaDLayV7fU","confirmations":203,"script":{"invocation":"40445e8de1ba402cab0bffedc32840b3587c8f6b272c02ea2b4a609419fbcb85a3cf5cd183ea7d28788eb19a12265be1d2f43f7986de66c8d8585d66825a0701fc40d935dfb83310d3433a7afc0bbb15f4c0686a624734cee6f6b98d5d95e660401c5b35c7cfd802fa82759aab288373ad894d82056d29109e6142d8c1397f60706f4076e9fd7bef3b9a8ce12904414cc55293161bcb536a4939200dd3c586c4d60ded565780d307598b8dcf4eebb64f53cc9fc0c381d47e58b7cec1b9392097a2b3ec407b03a25d83d429810b7a929f48b8125d3bfff5982f876c0dbd1d9dbbf08534d3235a4709c7f779449ed865ca1d2e29729c0210174782869a09c2b821bd15fda1","verification":"532102103a7f7dd016558597f7960d27c516a4394fd968b9e65155eb4b013e4040406e2102a7bc55fe8684e0119768d104ba30795bdcc86619e864add26156723ed185cd622102b3622bf4017bdfe317c58aed5f4c753f206b7db896046fa7d774bbc4bf7f8dc22103d90c07df63e690ce77912e10ab51acc944b66860237b608c4f8f8309e71ee69954ae"},"tx":[{"sys_fee":"0","net_fee":"0","txid":"0x9cd542123b6ce63d9285ab5df999649e4f6501949c6bcd8aa4bdd19a8434bdf0","size":14,"type":"MinerTransaction","version":0,"nonce":1237,"valid_until_block":5,"attributes":[],"vin":[],"vout":[],"scripts":[]}]}}`, result: func(c *Client) interface{} { - hash, err := util.Uint256DecodeStringLE("e93d17a52967f9e69314385482bf86f85260e811b46bf4d4b261a7f4135a623c") + hash, err := util.Uint256DecodeStringLE("a928e6e394bbc8ebb02b88fa14efb2860c9de376b4809ba078e7e47ca9a77af9") if err != nil { panic(err) } - nextBlockHash, err := util.Uint256DecodeStringLE("cc37d5bc460e72c9423015cb8d579c13e7b03b93bfaa1a23cf4fa777988e035f") + nextBlockHash, err := util.Uint256DecodeStringLE("5ff4068d996cbefb6fb6e36f6c8085a79f7ab28cc3149b6f49a55cf97fa4b513") if err != nil { panic(err) } - prevBlockHash, err := util.Uint256DecodeStringLE("996e37358dc369912041f966f8c5d8d3a8255ba5dcbd3447f8a82b55db869099") + prevBlockHash, err := util.Uint256DecodeStringLE("854eb21e4e38c44c37fdf1e37d0322dcf41086ccff0c98f499d85fad48458ca7") if err != nil { panic(err) } - merkleRoot, err := util.Uint256DecodeStringLE("cb6ddb5f99d6af4c94a6c396d5294472f2eebc91a2c933e0f527422296fa9fb2") + merkleRoot, err := util.Uint256DecodeStringLE("9cd542123b6ce63d9285ab5df999649e4f6501949c6bcd8aa4bdd19a8434bdf0") if err != nil { panic(err) } - invScript, err := hex.DecodeString("40356a91d94e398170e47447d6a0f60aa5470e209782a5452403115a49166db3e1c4a3898122db19f779c30f8ccd0b7d401acdf71eda340655e4ae5237a64961bf4034dd47955e5a71627dafc39dd92999140e9eaeec6b11dbb2b313efa3f1093ed915b4455e199c69ec53778f94ffc236b92f8b97fff97a1f6bbb3770c0c0b3844a40fbe743bd5c90b2f5255e0b073281d7aeb2fb516572f36bec8446bcc37ac755cbf10d08b16c95644db1b2dddc2df5daa377880b20198fc7b967ac6e76474b22df") + invScript, err := hex.DecodeString("40445e8de1ba402cab0bffedc32840b3587c8f6b272c02ea2b4a609419fbcb85a3cf5cd183ea7d28788eb19a12265be1d2f43f7986de66c8d8585d66825a0701fc40d935dfb83310d3433a7afc0bbb15f4c0686a624734cee6f6b98d5d95e660401c5b35c7cfd802fa82759aab288373ad894d82056d29109e6142d8c1397f60706f4076e9fd7bef3b9a8ce12904414cc55293161bcb536a4939200dd3c586c4d60ded565780d307598b8dcf4eebb64f53cc9fc0c381d47e58b7cec1b9392097a2b3ec407b03a25d83d429810b7a929f48b8125d3bfff5982f876c0dbd1d9dbbf08534d3235a4709c7f779449ed865ca1d2e29729c0210174782869a09c2b821bd15fda1") if err != nil { panic(err) } @@ -266,21 +269,22 @@ var rpcClientTestCases = map[string][]rpcClientTestCase{ if err != nil { panic(err) } - tx := transaction.NewMinerTXWithNonce(4266257741) + tx := transaction.NewMinerTXWithNonce(1237) + tx.ValidUntilBlock = 5 // Update hashes for correct result comparison. _ = tx.Hash() return &result.Block{ Hash: hash, - Size: 452, + Size: 523, Version: 0, NextBlockHash: &nextBlockHash, PreviousBlockHash: prevBlockHash, MerkleRoot: merkleRoot, - Time: 1541215200, - Index: 1, - Nonce: "51b484a2fe49ed4d", + Time: 1586859653, + Index: 5, + Nonce: "0000000000000457", NextConsensus: "AZ81H31DMWzbSnFDLFkzh9vHwaDLayV7fU", - Confirmations: 10534, + Confirmations: 203, Script: transaction.Witness{ InvocationScript: invScript, VerificationScript: verifScript, @@ -606,19 +610,19 @@ var rpcClientTestCases = map[string][]rpcClientTestCase{ { name: "positive", invoke: func(c *Client) (i interface{}, err error) { - hash, err := util.Uint256DecodeStringLE("cb6ddb5f99d6af4c94a6c396d5294472f2eebc91a2c933e0f527422296fa9fb2") + hash, err := util.Uint256DecodeStringLE("0b698b4ac68fc3206e65868e8f51ea5ac29e92b5faf9e79562cd57fc744d47c5") if err != nil { panic(err) } return c.GetRawTransaction(hash) }, - serverResponse: `{"id":1,"jsonrpc":"2.0","result":"00004ded49fe00000000"}`, + serverResponse: `{"id":1,"jsonrpc":"2.0","result":"00001dac2b7c0100000000000000"}`, result: func(c *Client) interface{} { return &transaction.Transaction{} }, check: func(t *testing.T, c *Client, result interface{}) { res, ok := result.(*transaction.Transaction) require.True(t, ok) assert.Equal(t, uint8(0), res.Version) - assert.Equal(t, "cb6ddb5f99d6af4c94a6c396d5294472f2eebc91a2c933e0f527422296fa9fb2", res.Hash().StringLE()) + assert.Equal(t, "0b698b4ac68fc3206e65868e8f51ea5ac29e92b5faf9e79562cd57fc744d47c5", res.Hash().StringBE()) assert.Equal(t, transaction.MinerType, res.Type) assert.Equal(t, false, res.Trimmed) }, @@ -626,19 +630,20 @@ var rpcClientTestCases = map[string][]rpcClientTestCase{ { name: "verbose_positive", invoke: func(c *Client) (interface{}, error) { - hash, err := util.Uint256DecodeStringLE("cb6ddb5f99d6af4c94a6c396d5294472f2eebc91a2c933e0f527422296fa9fb2") + hash, err := util.Uint256DecodeStringLE("0b698b4ac68fc3206e65868e8f51ea5ac29e92b5faf9e79562cd57fc744d47c5") if err != nil { panic(err) } return c.GetRawTransactionVerbose(hash) }, - serverResponse: `{"id":1,"jsonrpc":"2.0","result":{"nonce":4266257741,"type":"MinerTransaction","version":0,"attributes":[],"vin":[],"vout":[],"scripts":[],"txid":"0xcb6ddb5f99d6af4c94a6c396d5294472f2eebc91a2c933e0f527422296fa9fb2","size":10,"sys_fee":"0","net_fee":"0","blockhash":"0xe93d17a52967f9e69314385482bf86f85260e811b46bf4d4b261a7f4135a623c","confirmations":20875,"blocktime":1541215200}}`, + serverResponse: `{"jsonrpc":"2.0","id":1,"result":{"sys_fee":"0","net_fee":"0","blockhash":"0x77007ec4921dd78e91c26bee9c14b49148ae08140f698accea49ecc279e68435","confirmations":210,"blocktime":1468595301,"txid":"0xc5474d74fc57cd6295e7f9fab5929ec25aea518f8e86656e20c38fc64a8b690b","size":14,"type":"MinerTransaction","version":0,"nonce":2083236893,"valid_until_block":1,"attributes":[],"vin":[],"vout":[],"scripts":[]}}`, result: func(c *Client) interface{} { - blockHash, err := util.Uint256DecodeStringLE("e93d17a52967f9e69314385482bf86f85260e811b46bf4d4b261a7f4135a623c") + blockHash, err := util.Uint256DecodeStringLE("77007ec4921dd78e91c26bee9c14b49148ae08140f698accea49ecc279e68435") if err != nil { panic(err) } - tx := transaction.NewMinerTXWithNonce(4266257741) + tx := transaction.NewMinerTXWithNonce(2083236893) + tx.ValidUntilBlock = 1 // Update hashes for correct result comparison. _ = tx.Hash() @@ -648,8 +653,8 @@ var rpcClientTestCases = map[string][]rpcClientTestCase{ SysFee: 0, NetFee: 0, Blockhash: blockHash, - Confirmations: 20875, - Timestamp: uint32(1541215200), + Confirmations: 210, + Timestamp: uint32(1468595301), }, } }, @@ -1438,3 +1443,50 @@ func requestHandler(t *testing.T, w http.ResponseWriter, resp string) { t.Fatalf("Error encountered while encoding response: %s", err.Error()) } } + +func TestCalculateValidUntilBlock(t *testing.T) { + var ( + getBlockCountCalled int + getValidatorsCalled int + ) + srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { + r := request.NewIn() + err := r.DecodeData(req.Body) + if err != nil { + t.Fatalf("Cannot decode request body: %s", req.Body) + } + var response string + switch r.Method { + case "getblockcount": + getBlockCountCalled++ + response = `{"jsonrpc":"2.0","id":1,"result":50}` + case "getvalidators": + getValidatorsCalled++ + response = `{"id":1,"jsonrpc":"2.0","result":[{"publickey":"02b3622bf4017bdfe317c58aed5f4c753f206b7db896046fa7d774bbc4bf7f8dc2","votes":"0","active":true},{"publickey":"02103a7f7dd016558597f7960d27c516a4394fd968b9e65155eb4b013e4040406e","votes":"0","active":true},{"publickey":"03d90c07df63e690ce77912e10ab51acc944b66860237b608c4f8f8309e71ee699","votes":"0","active":true},{"publickey":"02a7bc55fe8684e0119768d104ba30795bdcc86619e864add26156723ed185cd62","votes":"0","active":true}]}` + default: + t.Fatalf("Bad request method: %s", r.Method) + } + requestHandler(t, w, response) + })) + defer srv.Close() + + endpoint := srv.URL + opts := Options{} + c, err := New(context.TODO(), endpoint, opts) + if err != nil { + t.Fatal(err) + } + + validUntilBlock, err := c.CalculateValidUntilBlock() + assert.NoError(t, err) + assert.Equal(t, uint32(54), validUntilBlock) + assert.Equal(t, 1, getBlockCountCalled) + assert.Equal(t, 1, getValidatorsCalled) + + // check, whether caching is working + validUntilBlock, err = c.CalculateValidUntilBlock() + assert.NoError(t, err) + assert.Equal(t, uint32(54), validUntilBlock) + assert.Equal(t, 2, getBlockCountCalled) + assert.Equal(t, 1, getValidatorsCalled) +} diff --git a/pkg/rpc/server/server_test.go b/pkg/rpc/server/server_test.go index b4a7ff552..1a0108ce8 100644 --- a/pkg/rpc/server/server_test.go +++ b/pkg/rpc/server/server_test.go @@ -49,14 +49,14 @@ var rpcTestCases = map[string][]rpcTestCase{ "getapplicationlog": { { name: "positive", - params: `["0d77a6c348097c4b29fd9d0fe8657c621bc7d804034c71272e3c4f13775138f2"]`, + params: `["e5a6be3cd796e2284a55ebb2061f85d3f199263bbf659dbd5b670a6506e7a4a0"]`, result: func(e *executor) interface{} { return &result.ApplicationLog{} }, check: func(t *testing.T, e *executor, acc interface{}) { res, ok := acc.(*result.ApplicationLog) require.True(t, ok) - expectedTxHash, err := util.Uint256DecodeStringLE("0d77a6c348097c4b29fd9d0fe8657c621bc7d804034c71272e3c4f13775138f2") + expectedTxHash, err := util.Uint256DecodeStringLE("e5a6be3cd796e2284a55ebb2061f85d3f199263bbf659dbd5b670a6506e7a4a0") require.NoError(t, err) assert.Equal(t, expectedTxHash, res.TxHash) assert.Equal(t, 1, len(res.Executions)) @@ -251,7 +251,7 @@ var rpcTestCases = map[string][]rpcTestCase{ "getassetstate": { { name: "positive", - params: `["057ea06225860f0f7e69cca1e0052652918629929591b8138a516431be144ba8"]`, + params: `["8dd7d330dd7fc103836409bdcba826d15d88119c7f843357266b253aede72dfb"]`, result: func(e *executor) interface{} { return &result.AssetState{} }, check: func(t *testing.T, e *executor, as interface{}) { res, ok := as.(*result.AssetState) @@ -405,25 +405,25 @@ var rpcTestCases = map[string][]rpcTestCase{ "getblockheader": { { name: "positive, no verbose", - params: `["7c32645dab0d87cfaddd5db053e2430c669f807e9efc2b91d1f50a824893352f"]`, + params: `["02b9e6f634578f34c6026f1676e25aa04f58889a320fba8bc632c6fe48c26cf1"]`, result: func(e *executor) interface{} { - expected := "000000002534685cc322d339f957ea368a654bf30b834be4cac0b8441375cce2a37630625507db78d2a2f3130c6073bd68f57202248fdc8966fa8706e88eb0fc61df74085384945e010000005704000000000000be48d3a3f5d10013ab9ffee489706078714f1ea201fd040140b622b3bdddb8c5e52ae8b4bce5665eb6e2aca950ba72386ea0d37e364af2c7fc40f009c47e1a2140bee90d1e2f81c705d6f2499fe6230b27d1f225c45f38d3c440ec01e743024c2c63dccb2ca4a555eeadb2e6115fe6bc42a8d5c17093828e4ea779b36c6d1535c70c047c709183fc1c93139153291dd0edb614dd3e17d67038dd400f7635816214254b7fba0bb480e2a0ab149c84854adcb542124e67f4cedbf551690f8048271c3f05bbe50f576dcbaf3607afffa2551480cdc24908df0fd47c60408d724d6cfb9bf99e38dc42974f084d110057d3f23a04f5bbf99f5712dad17ae842416bb3e30fee034a317280565cb772f8a61fd09cb05e76db27c5fc7722819f8b532102103a7f7dd016558597f7960d27c516a4394fd968b9e65155eb4b013e4040406e2102a7bc55fe8684e0119768d104ba30795bdcc86619e864add26156723ed185cd622102b3622bf4017bdfe317c58aed5f4c753f206b7db896046fa7d774bbc4bf7f8dc22103d90c07df63e690ce77912e10ab51acc944b66860237b608c4f8f8309e71ee69954ae00" + expected := "000000009456b8c7f89bdfe012a30a2be9af5218e048ae7372115ce3e39cc847c01e9e7f9cffa26c112eb147a995520e47afbc45a192d9bf1a8e9b8f80497e5d92c4e9f2129e965e010000005704000000000000be48d3a3f5d10013ab9ffee489706078714f1ea201fd0401408ee2187395071a089e3b9743b1a718fa28a8700676451317f7454aade98cf779b0afb5634a7e104f92e2df8e8b1c1b7b3b0e9fd61f4c0e9ea07ce112cef12b9a40fcb441c89b0c2047ba71a86d759bc2554dda55369798e6ab63e6c7713b06a8178f13586edf6a673f20bf5ed7bdc727f9e0c6f487cf667e505a26236d73887ae940691972a6f4ccef19a03a3d5948dfcf992af2c6a3c5b033a0f9235d2b8967291d9f61495ff1a681f240517c8d892eaa805e667bca40abcf03d441c68a9ec59deb4005890a59d83c7cb0416895e4768123e900603d5b140bf799bc9879fb628c598193db2b7a8e07ab54733c1c67b60c97a1a8048961cc0afd0b048e878866ffd7298b532102103a7f7dd016558597f7960d27c516a4394fd968b9e65155eb4b013e4040406e2102a7bc55fe8684e0119768d104ba30795bdcc86619e864add26156723ed185cd622102b3622bf4017bdfe317c58aed5f4c753f206b7db896046fa7d774bbc4bf7f8dc22103d90c07df63e690ce77912e10ab51acc944b66860237b608c4f8f8309e71ee69954ae00" return &expected }, }, { name: "positive, verbose 0", - params: `["7c32645dab0d87cfaddd5db053e2430c669f807e9efc2b91d1f50a824893352f", 0]`, + params: `["02b9e6f634578f34c6026f1676e25aa04f58889a320fba8bc632c6fe48c26cf1", 0]`, result: func(e *executor) interface{} { - expected := "000000002534685cc322d339f957ea368a654bf30b834be4cac0b8441375cce2a37630625507db78d2a2f3130c6073bd68f57202248fdc8966fa8706e88eb0fc61df74085384945e010000005704000000000000be48d3a3f5d10013ab9ffee489706078714f1ea201fd040140b622b3bdddb8c5e52ae8b4bce5665eb6e2aca950ba72386ea0d37e364af2c7fc40f009c47e1a2140bee90d1e2f81c705d6f2499fe6230b27d1f225c45f38d3c440ec01e743024c2c63dccb2ca4a555eeadb2e6115fe6bc42a8d5c17093828e4ea779b36c6d1535c70c047c709183fc1c93139153291dd0edb614dd3e17d67038dd400f7635816214254b7fba0bb480e2a0ab149c84854adcb542124e67f4cedbf551690f8048271c3f05bbe50f576dcbaf3607afffa2551480cdc24908df0fd47c60408d724d6cfb9bf99e38dc42974f084d110057d3f23a04f5bbf99f5712dad17ae842416bb3e30fee034a317280565cb772f8a61fd09cb05e76db27c5fc7722819f8b532102103a7f7dd016558597f7960d27c516a4394fd968b9e65155eb4b013e4040406e2102a7bc55fe8684e0119768d104ba30795bdcc86619e864add26156723ed185cd622102b3622bf4017bdfe317c58aed5f4c753f206b7db896046fa7d774bbc4bf7f8dc22103d90c07df63e690ce77912e10ab51acc944b66860237b608c4f8f8309e71ee69954ae00" + expected := "000000009456b8c7f89bdfe012a30a2be9af5218e048ae7372115ce3e39cc847c01e9e7f9cffa26c112eb147a995520e47afbc45a192d9bf1a8e9b8f80497e5d92c4e9f2129e965e010000005704000000000000be48d3a3f5d10013ab9ffee489706078714f1ea201fd0401408ee2187395071a089e3b9743b1a718fa28a8700676451317f7454aade98cf779b0afb5634a7e104f92e2df8e8b1c1b7b3b0e9fd61f4c0e9ea07ce112cef12b9a40fcb441c89b0c2047ba71a86d759bc2554dda55369798e6ab63e6c7713b06a8178f13586edf6a673f20bf5ed7bdc727f9e0c6f487cf667e505a26236d73887ae940691972a6f4ccef19a03a3d5948dfcf992af2c6a3c5b033a0f9235d2b8967291d9f61495ff1a681f240517c8d892eaa805e667bca40abcf03d441c68a9ec59deb4005890a59d83c7cb0416895e4768123e900603d5b140bf799bc9879fb628c598193db2b7a8e07ab54733c1c67b60c97a1a8048961cc0afd0b048e878866ffd7298b532102103a7f7dd016558597f7960d27c516a4394fd968b9e65155eb4b013e4040406e2102a7bc55fe8684e0119768d104ba30795bdcc86619e864add26156723ed185cd622102b3622bf4017bdfe317c58aed5f4c753f206b7db896046fa7d774bbc4bf7f8dc22103d90c07df63e690ce77912e10ab51acc944b66860237b608c4f8f8309e71ee69954ae00" return &expected }, }, { name: "positive, verbose !=0", - params: `["7c32645dab0d87cfaddd5db053e2430c669f807e9efc2b91d1f50a824893352f", 2]`, + params: `["02b9e6f634578f34c6026f1676e25aa04f58889a320fba8bc632c6fe48c26cf1", 2]`, result: func(e *executor) interface{} { - hash, err := util.Uint256DecodeStringLE("7c32645dab0d87cfaddd5db053e2430c669f807e9efc2b91d1f50a824893352f") + hash, err := util.Uint256DecodeStringLE("02b9e6f634578f34c6026f1676e25aa04f58889a320fba8bc632c6fe48c26cf1") if err != nil { panic("can not decode hash parameter") } @@ -520,7 +520,7 @@ var rpcTestCases = map[string][]rpcTestCase{ params: `["AZ81H31DMWzbSnFDLFkzh9vHwaDLayV7fU"]`, result: func(*executor) interface{} { // hash of the issueTx - h, _ := util.Uint256DecodeStringBE("6a46738cd6f821d3b2d96e68c3feb5fcfe81d08a711baadbb68cbfb034fa29c5") + h, _ := util.Uint256DecodeStringBE("7b5710faf4ea62e3cd7f526d3dad39e85e1823c62340c88b80e36fd99342457a") amount := util.Fixed8FromInt64(1 * 8) // (endHeight - startHeight) * genAmount[0] return &result.ClaimableInfo{ Spents: []result.Claimable{ @@ -579,7 +579,7 @@ var rpcTestCases = map[string][]rpcTestCase{ "gettransactionheight": { { name: "poositive", - params: `["3fe72668fa667b8bb0a77ac2375402d52fafc18e6d0a4c12a401dc69bdf515c2"]`, + params: `["2f0ed00979cb5feae842946be2afb96deec9c13236605fda63737db223089a00"]`, result: func(e *executor) interface{} { h := 1 return &h @@ -791,7 +791,7 @@ var rpcTestCases = map[string][]rpcTestCase{ "sendrawtransaction": { { name: "positive", - params: `["80001300000000015b090ad71ea0c192adc820401b2edc6a197788ee8e5e42a9c5e5e00d700c5da1010001250815d6e93c89e6d2f7279bd5781317d1bfb1ee30aca4c338524654563b3acd0030d3dec38623002baa76ad534b886cb87c6b3720a34943d9000fa90141409646e3dd0dd87685eadac1f682fa63db83729f780a7b2e739cb372ceeaadb3f19260060b34c83fec46e48a6288b2bc5c641e75d1cb358e9c185425a2e6e3fdab232102b3622bf4017bdfe317c58aed5f4c753f206b7db896046fa7d774bbc4bf7f8dc2ac"]`, + params: `["800013000000b004000000010655773cea2a4f8cc66f83989605a58e87e885b6aaf58d450db3b83f81a2c950010001a9bf999e43ccfe9d40c3450fc75ca4b02db9b1691a7e1989b331f621456289050030d3dec38623002baa76ad534b886cb87c6b3720a34943d9000fa9014140faa7f2c3f700838aa48be950aff762c050f1cf04f1185fb3893820f63a98ccbfed05e8c5931f67ade59054c853be1d37ff9e75ed65b0543255ff28a3f8667670232102b3622bf4017bdfe317c58aed5f4c753f206b7db896046fa7d774bbc4bf7f8dc2ac"]`, result: func(e *executor) interface{} { v := true return &v @@ -822,7 +822,7 @@ var rpcTestCases = map[string][]rpcTestCase{ { // If you are planning to modify test chain from `testblocks.acc`, please, update param value (first block) name: "empty block", - params: `["00000000565f6b8fab486930d5ece5feb93060f010b556b2d4aa618878326ed93604ed6400000000000000000000000000000000000000000000000000000000000000002385945ed10000005704000000000000be48d3a3f5d10013ab9ffee489706078714f1ea201fd0401408313b36a61c137d327bec8791dfbb22ae9627fbcd2b023236f65188376f1ff4913c554b276cf7e84c5446fb495df2ed7cd34577ef9a4f9dd0dd27654aa53abe040acf3d5327c50e08bf97d794b6ec021223b8c493f9b71f8844446a01a99e555d517d30b84cbb2a5dcbafb5171373f4d0e6c8aea54f46901455d62545f75bdd2a640c359e2365bfe6f9b7b58a09e7e78f2bee85dbb4f823f9bee31b297cb2eb804eb4a5f1858a729d9676ab2c63b91bee5726c7b38086a04f3fe0ca23155331c476840dfddf4c173a374aacff6d2f37b327256556aa37d7c38c41dfda1f42d25f33d921b41da271aa27f7872f7b2b0b00f90a7ee83f5823ea1cc4f9db90a0100a8b7868b532102103a7f7dd016558597f7960d27c516a4394fd968b9e65155eb4b013e4040406e2102a7bc55fe8684e0119768d104ba30795bdcc86619e864add26156723ed185cd622102b3622bf4017bdfe317c58aed5f4c753f206b7db896046fa7d774bbc4bf7f8dc22103d90c07df63e690ce77912e10ab51acc944b66860237b608c4f8f8309e71ee69954ae00"]`, + params: `["0000000029e2ea0ec5c9aa98fa736b52750916b3b8ab5cdbe7647fb6d0b7f6dac35865640000000000000000000000000000000000000000000000000000000000000000e29e965ed10000005704000000000000be48d3a3f5d10013ab9ffee489706078714f1ea201fd040140efdc94ac1e5c7588a1e70aa2ada3450631f30b15676861e7f32159f0e0b97e5fec8dd9870d92755e76b2cf3d6a90f06c2f6a7b782248ac4b765433beb6891a4840551f59a1e88395290ea2273500c60fc55b0d33ab6c3ddd565177f77083e82aaffca3553a0a116b457d5101f8627da39a3a24f19e2d04fab7e65670fda6a50f4140576969f478e6150b128b1149dd3c8b663f27bda53a6815fe177d52abc6ad40311a4fcba14a0d9286d6cda521cd9bc0ade09a66e88059da84363512c6110f4dc94008e8c0e6f3835281690fa0d594a6f5f1914b2f047fe835b134641b5a19935a4f6b10931ad168e47f96f6bf98380c0f060d4b25ae71869c4ef9d2a92a262eceeb8b532102103a7f7dd016558597f7960d27c516a4394fd968b9e65155eb4b013e4040406e2102a7bc55fe8684e0119768d104ba30795bdcc86619e864add26156723ed185cd622102b3622bf4017bdfe317c58aed5f4c753f206b7db896046fa7d774bbc4bf7f8dc22103d90c07df63e690ce77912e10ab51acc944b66860237b608c4f8f8309e71ee69954ae00"]`, fail: true, }, { @@ -848,7 +848,7 @@ var rpcTestCases = map[string][]rpcTestCase{ { name: "positive", // If you are planning to modify test chain from `testblocks.acc`, please, update param value (second block) - params: `["00000000565f6b8fab486930d5ece5feb93060f010b556b2d4aa618878326ed93604ed645c23aae5b26be3d759680239a4276be0d2e76de303ef3fda96da97e8a3f6a0f12385945ed10000005704000000000000be48d3a3f5d10013ab9ffee489706078714f1ea201fd040140accd1571b3c25e4a6ec80f3bfc8ca3360f51232ed615b756e88424c1c083bd4c0d37f98156c8b87a36710467a75ff3938acea5bbd6a683d439004e2a30665562405de64537c7a411055504bec46851101a3ee9a3db02a7fb0feff781bee43a71ff7e76e03f273437bb94ad1f58dbe29eff32d9299bae0f48860a89a74ed5a48900400a337ce23f8dd767d043ba2b0886ba25d3905a1493ba70a96b297179914d096dfb8621f40e5efa63205af46b8ae71198846affcf02b9137752fcf3d54a683faa408d54fcd4d5235ff48b8dbe7d6f2e0b75ea3dc1bcd563ae44c8c8df201f5039fd30357d8c6709a0639a4aef07a223ca2ae21a74494808bc8b8f2955e7b26bdd148b532102103a7f7dd016558597f7960d27c516a4394fd968b9e65155eb4b013e4040406e2102a7bc55fe8684e0119768d104ba30795bdcc86619e864add26156723ed185cd622102b3622bf4017bdfe317c58aed5f4c753f206b7db896046fa7d774bbc4bf7f8dc22103d90c07df63e690ce77912e10ab51acc944b66860237b608c4f8f8309e71ee69954ae0100001400000000000000"]`, + params: `["0000000029e2ea0ec5c9aa98fa736b52750916b3b8ab5cdbe7647fb6d0b7f6dac3586564980135e10c52e5444c962659b388a5b226114a45d3912a88700ac6b05aaaf961e29e965ed10000005704000000000000be48d3a3f5d10013ab9ffee489706078714f1ea201fd040140a0ed19af416fc4edb6e32b4687290d4eff1262af338dc8e55021a13f500ce94377c0fca593db15e29a0ee11b229d8bb48bd75203834829aee47096ff375ef8e240bcccad08d1ae7cc47c099eb4321a1fe07cf77a434841fd48a04aaf19204ec5bbf465533a2845a323710ea068316f50be82c384c82e0a5a509b2a9442c6a7909640de0a52dd615efac136971be900700ec39a84198e7d1639e880955022901a8d98ff39f00e858b41686047d68d7c18963b9def50a85907eb3b0bfbba7b2fa64d814060670b0c648757594cdba09aafc158ee6f7e88fbd2aa088a8c57bff2c8e7ddd83fa242632e1b6f82e3af2b3d0428c3936833cefb7ced1cc3c50ec29da906eb498b532102103a7f7dd016558597f7960d27c516a4394fd968b9e65155eb4b013e4040406e2102a7bc55fe8684e0119768d104ba30795bdcc86619e864add26156723ed185cd622102b3622bf4017bdfe317c58aed5f4c753f206b7db896046fa7d774bbc4bf7f8dc22103d90c07df63e690ce77912e10ab51acc944b66860237b608c4f8f8309e71ee69954ae01000014000000b004000000000000"]`, result: func(e *executor) interface{} { v := true return &v @@ -921,7 +921,7 @@ func TestRPC(t *testing.T) { var res string err := json.Unmarshal(result, &res) require.NoErrorf(t, err, "could not parse response: %s", result) - assert.Equal(t, "40000000000000455b7b226c616e67223a227a682d434e222c226e616d65223a22e5b08fe89a81e882a1227d2c7b226c616e67223a22656e222c226e616d65223a22416e745368617265227d5d0000c16ff28623000000da1745e9b549bd0bfa1a569971c77eba30cd5a4b00000000", res) + assert.Equal(t, "4000000000000000000000455b7b226c616e67223a227a682d434e222c226e616d65223a22e5b08fe89a81e882a1227d2c7b226c616e67223a22656e222c226e616d65223a22416e745368617265227d5d0000c16ff28623000000da1745e9b549bd0bfa1a569971c77eba30cd5a4b00000000", res) }) t.Run("getrawtransaction 2 arguments", func(t *testing.T) { @@ -933,7 +933,7 @@ func TestRPC(t *testing.T) { var res string err := json.Unmarshal(result, &res) require.NoErrorf(t, err, "could not parse response: %s", result) - assert.Equal(t, "40000000000000455b7b226c616e67223a227a682d434e222c226e616d65223a22e5b08fe89a81e882a1227d2c7b226c616e67223a22656e222c226e616d65223a22416e745368617265227d5d0000c16ff28623000000da1745e9b549bd0bfa1a569971c77eba30cd5a4b00000000", res) + assert.Equal(t, "4000000000000000000000455b7b226c616e67223a227a682d434e222c226e616d65223a22e5b08fe89a81e882a1227d2c7b226c616e67223a22656e222c226e616d65223a22416e745368617265227d5d0000c16ff28623000000da1745e9b549bd0bfa1a569971c77eba30cd5a4b00000000", res) }) t.Run("getrawtransaction 2 arguments, verbose", func(t *testing.T) { @@ -973,7 +973,7 @@ func TestRPC(t *testing.T) { err := json.Unmarshal(res, &txOut) require.NoErrorf(t, err, "could not parse response: %s", res) assert.Equal(t, 0, txOut.N) - assert.Equal(t, "0x250815d6e93c89e6d2f7279bd5781317d1bfb1ee30aca4c338524654563b3acd", txOut.Asset) + assert.Equal(t, "0xa9bf999e43ccfe9d40c3450fc75ca4b02db9b1691a7e1989b331f62145628905", txOut.Asset) assert.Equal(t, util.Fixed8FromInt64(100000000), txOut.Value) assert.Equal(t, "AZ81H31DMWzbSnFDLFkzh9vHwaDLayV7fU", txOut.Address) }) diff --git a/pkg/rpc/server/testdata/testblocks.acc b/pkg/rpc/server/testdata/testblocks.acc index a851b16b3..33aa0230f 100644 Binary files a/pkg/rpc/server/testdata/testblocks.acc and b/pkg/rpc/server/testdata/testblocks.acc differ