github.com/igggame/nebulas-go@v2.1.0+incompatible/core/transaction_test.go (about)

     1  // Copyright (C) 2017 go-nebulas authors
     2  //
     3  // This file is part of the go-nebulas library.
     4  //
     5  // the go-nebulas library is free software: you can redistribute it and/or modify
     6  // it under the terms of the GNU General Public License as published by
     7  // the Free Software Foundation, either version 3 of the License, or
     8  // (at your option) any later version.
     9  //
    10  // the go-nebulas library is distributed in the hope that it will be useful,
    11  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    12  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    13  // GNU General Public License for more details.
    14  //
    15  // You should have received a copy of the GNU General Public License
    16  // along with the go-nebulas library.  If not, see <http://www.gnu.org/licenses/>.
    17  //
    18  
    19  package core
    20  
    21  import (
    22  	"encoding/json"
    23  	"fmt"
    24  	"reflect"
    25  	"testing"
    26  	"time"
    27  
    28  	"github.com/gogo/protobuf/proto"
    29  	"github.com/nebulasio/go-nebulas/core/pb"
    30  	"github.com/nebulasio/go-nebulas/crypto"
    31  	"github.com/nebulasio/go-nebulas/crypto/hash"
    32  	"github.com/nebulasio/go-nebulas/crypto/keystore"
    33  	"github.com/nebulasio/go-nebulas/util"
    34  	"github.com/nebulasio/go-nebulas/util/byteutils"
    35  	"github.com/stretchr/testify/assert"
    36  )
    37  
    38  func mockNormalTransaction(chainID uint32, nonce uint64) *Transaction {
    39  	// payload, _ := NewBinaryPayload(nil).ToBytes()
    40  	return mockTransaction(chainID, nonce, TxPayloadBinaryType, nil)
    41  }
    42  
    43  func mockDeployTransaction(chainID uint32, nonce uint64) *Transaction {
    44  	source := `
    45  	"use strict";var StandardToken=function(){LocalContractStorage.defineProperties(this,{name:null,symbol:null,_totalSupply:null,totalIssued:null});LocalContractStorage.defineMapProperty(this,"balances")};StandardToken.prototype={init:function(name,symbol,totalSupply){this.name=name;this.symbol=symbol;this._totalSupply=totalSupply;this.totalIssued=0},totalSupply:function(){return this._totalSupply},balanceOf:function(owner){return this.balances.get(owner)||0},transfer:function(to,value){var balance=this.balanceOf(msg.sender);if(balance<value){return false}var finalBalance=balance-value;this.balances.set(msg.sender,finalBalance);this.balances.set(to,this.balanceOf(to)+value);return true},pay:function(msg,amount){if(this.totalIssued+amount>this._totalSupply){throw new Error("too much amount, exceed totalSupply")}this.balances.set(msg.sender,this.balanceOf(msg.sender)+amount);this.totalIssued+=amount}};module.exports=StandardToken;
    46  	`
    47  	sourceType := "js"
    48  	args := `["NebulasToken", "NAS", 1000000000]`
    49  	payloadObj, _ := NewDeployPayload(source, sourceType, args)
    50  	payload, _ := payloadObj.ToBytes()
    51  	return mockTransaction(chainID, nonce, TxPayloadDeployType, payload)
    52  }
    53  
    54  func mockCallTransaction(chainID uint32, nonce uint64, function, args string) *Transaction {
    55  	callpayload, _ := NewCallPayload(function, args)
    56  	payload, _ := callpayload.ToBytes()
    57  	return mockTransaction(chainID, nonce, TxPayloadCallType, payload)
    58  }
    59  
    60  func mockTransaction(chainID uint32, nonce uint64, payloadType string, payload []byte) *Transaction {
    61  	from := mockAddress()
    62  	to := mockAddress()
    63  	if payloadType == TxPayloadDeployType {
    64  		to = from
    65  	}
    66  	tx, _ := NewTransaction(chainID, from, to, util.NewUint128(), nonce, payloadType, payload, TransactionGasPrice, TransactionMaxGas)
    67  	return tx
    68  }
    69  
    70  func TestTransaction(t *testing.T) {
    71  	type fields struct {
    72  		hash      byteutils.Hash
    73  		from      *Address
    74  		to        *Address
    75  		value     *util.Uint128
    76  		nonce     uint64
    77  		timestamp int64
    78  		alg       uint8
    79  		data      *corepb.Data
    80  		gasPrice  *util.Uint128
    81  		gasLimit  *util.Uint128
    82  	}
    83  	gasPrice, _ := util.NewUint128FromInt(1)
    84  	gasLimit, _ := util.NewUint128FromInt(1)
    85  	tests := []struct {
    86  		name   string
    87  		fields fields
    88  	}{
    89  		{
    90  			"full struct",
    91  			fields(fields{
    92  				[]byte("123455"),
    93  				mockAddress(),
    94  				mockAddress(),
    95  				util.NewUint128(),
    96  				456,
    97  				time.Now().Unix(),
    98  				uint8(keystore.SECP256K1),
    99  				&corepb.Data{Type: TxPayloadBinaryType, Payload: []byte("hwllo")},
   100  				gasPrice,
   101  				gasLimit,
   102  			}),
   103  		},
   104  	}
   105  	for _, tt := range tests {
   106  		t.Run(tt.name, func(t *testing.T) {
   107  			tx := &Transaction{
   108  				hash:      tt.fields.hash,
   109  				from:      tt.fields.from,
   110  				to:        tt.fields.to,
   111  				value:     tt.fields.value,
   112  				nonce:     tt.fields.nonce,
   113  				timestamp: tt.fields.timestamp,
   114  				alg:       keystore.Algorithm(tt.fields.alg),
   115  				data:      tt.fields.data,
   116  				gasPrice:  tt.fields.gasPrice,
   117  				gasLimit:  tt.fields.gasLimit,
   118  			}
   119  			msg, _ := tx.ToProto()
   120  			ir, _ := proto.Marshal(msg)
   121  			ntx := new(Transaction)
   122  			nMsg := new(corepb.Transaction)
   123  			proto.Unmarshal(ir, nMsg)
   124  			ntx.FromProto(nMsg)
   125  			ntx.timestamp = tx.timestamp
   126  			if !reflect.DeepEqual(tx, ntx) {
   127  				t.Errorf("Transaction.Serialize() = %v, want %v", *tx, *ntx)
   128  			}
   129  		})
   130  	}
   131  }
   132  
   133  func TestTransaction_VerifyIntegrity(t *testing.T) {
   134  	testCount := 3
   135  	type testTx struct {
   136  		name   string
   137  		tx     *Transaction
   138  		signer keystore.Signature
   139  		count  int
   140  	}
   141  
   142  	tests := []testTx{}
   143  	ks := keystore.DefaultKS
   144  
   145  	for index := 0; index < testCount; index++ {
   146  
   147  		from := mockAddress()
   148  		to := mockAddress()
   149  
   150  		key1, _ := ks.GetUnlocked(from.String())
   151  		signature, _ := crypto.NewSignature(keystore.SECP256K1)
   152  		signature.InitSign(key1.(keystore.PrivateKey))
   153  
   154  		gasLimit, _ := util.NewUint128FromInt(200000)
   155  		tx, _ := NewTransaction(1, from, to, util.NewUint128(), 10, TxPayloadBinaryType, []byte("datadata"), TransactionGasPrice, gasLimit)
   156  
   157  		test := testTx{string(index), tx, signature, 1}
   158  		tests = append(tests, test)
   159  	}
   160  	for _, tt := range tests {
   161  		for index := 0; index < tt.count; index++ {
   162  			t.Run(tt.name, func(t *testing.T) {
   163  				err := tt.tx.Sign(tt.signer)
   164  				if err != nil {
   165  					t.Errorf("Sign() error = %v", err)
   166  					return
   167  				}
   168  				err = tt.tx.VerifyIntegrity(tt.tx.chainID)
   169  				if err != nil {
   170  					t.Errorf("verify failed:%s", err)
   171  					return
   172  				}
   173  			})
   174  		}
   175  	}
   176  }
   177  
   178  func TestTransaction_VerifyExecutionDependency(t *testing.T) {
   179  
   180  	neb := testNeb(t)
   181  	bc := neb.chain
   182  
   183  	a := mockAddress()
   184  	b := mockAddress()
   185  	c := mockAddress()
   186  	e := mockAddress()
   187  	f := mockAddress()
   188  
   189  	ks := keystore.DefaultKS
   190  
   191  	v, _ := util.NewUint128FromInt(1)
   192  	tx1, _ := NewTransaction(bc.chainID, a, b, v, uint64(1), TxPayloadBinaryType, []byte("nas"), TransactionGasPrice, TransactionMaxGas)
   193  	tx2, _ := NewTransaction(bc.chainID, a, b, v, uint64(2), TxPayloadBinaryType, []byte("nas"), TransactionGasPrice, TransactionMaxGas)
   194  	tx3, _ := NewTransaction(bc.chainID, b, c, v, uint64(1), TxPayloadBinaryType, []byte("nas"), TransactionGasPrice, TransactionMaxGas)
   195  	tx4, _ := NewTransaction(bc.chainID, e, f, v, uint64(1), TxPayloadBinaryType, []byte("nas"), TransactionGasPrice, TransactionMaxGas)
   196  
   197  	txs := [4]*Transaction{tx1, tx2, tx3, tx4}
   198  	for _, tx := range txs {
   199  		key, _ := ks.GetUnlocked(tx.from.String())
   200  		signature, _ := crypto.NewSignature(keystore.SECP256K1)
   201  		signature.InitSign(key.(keystore.PrivateKey))
   202  		assert.Nil(t, tx.Sign(signature))
   203  	}
   204  
   205  	balance, _ := util.NewUint128FromString("1000000000000000000")
   206  
   207  	bc.tailBlock.Begin()
   208  	{
   209  		fromAcc, err := bc.tailBlock.worldState.GetOrCreateUserAccount(tx1.from.address)
   210  		assert.Nil(t, err)
   211  		fromAcc.AddBalance(balance)
   212  	}
   213  	{
   214  		fromAcc, err := bc.tailBlock.worldState.GetOrCreateUserAccount(tx3.from.address)
   215  		assert.Nil(t, err)
   216  		fromAcc.AddBalance(balance)
   217  	}
   218  	{
   219  		fromAcc, err := bc.tailBlock.worldState.GetOrCreateUserAccount(tx4.from.address)
   220  		assert.Nil(t, err)
   221  		fromAcc.AddBalance(balance)
   222  	}
   223  
   224  	bc.tailBlock.Commit()
   225  
   226  	block, err := bc.NewBlock(bc.tailBlock.header.coinbase)
   227  	assert.Nil(t, err)
   228  	block.Begin()
   229  
   230  	//tx1
   231  	txWorldState1, err := block.WorldState().Prepare("1")
   232  	assert.Nil(t, err)
   233  	giveback, executionErr := VerifyExecution(tx1, block, txWorldState1)
   234  	assert.Nil(t, executionErr)
   235  	assert.False(t, giveback)
   236  	dependency1, err := txWorldState1.CheckAndUpdate()
   237  	assert.Nil(t, err)
   238  	assert.Equal(t, 0, len(dependency1))
   239  
   240  	acc1, err := block.worldState.GetOrCreateUserAccount(tx1.from.address)
   241  	assert.Equal(t, "999999999999999999", acc1.Balance().String())
   242  	toacc1, err := block.worldState.GetOrCreateUserAccount(tx1.to.address)
   243  	assert.Equal(t, "1000000000000000001", toacc1.Balance().String())
   244  
   245  	//tx2
   246  	txWorldState2, err := block.WorldState().Prepare("2")
   247  	txWorldState3, err := block.WorldState().Prepare("3")
   248  	txWorldState4, err := block.WorldState().Prepare("4")
   249  
   250  	giveback, executionErr2 := VerifyExecution(tx2, block, txWorldState2)
   251  	assert.Nil(t, executionErr2)
   252  	assert.False(t, giveback)
   253  	dependency2, err := txWorldState2.CheckAndUpdate()
   254  	assert.Nil(t, err)
   255  	assert.Equal(t, 1, len(dependency2))
   256  	assert.Equal(t, "1", dependency2[0])
   257  	acc2, err := block.worldState.GetOrCreateUserAccount(tx2.from.address)
   258  	assert.Equal(t, "999999999999999998", acc2.Balance().String())
   259  	toacc2, err := block.worldState.GetOrCreateUserAccount(tx2.to.address)
   260  	assert.Equal(t, "1000000000000000002", toacc2.Balance().String())
   261  
   262  	// tx3
   263  	giveback, executionErr3 := VerifyExecution(tx3, block, txWorldState3)
   264  	assert.NotNil(t, executionErr3)
   265  	assert.True(t, giveback)
   266  	txWorldState3.Close()
   267  
   268  	//tx4
   269  	giveback, executionErr4 := VerifyExecution(tx4, block, txWorldState4)
   270  	assert.Nil(t, executionErr4)
   271  	assert.False(t, giveback)
   272  	_, err4 := txWorldState4.CheckAndUpdate()
   273  	assert.Nil(t, err4)
   274  
   275  	txWorldState3, err = block.WorldState().Prepare("3")
   276  	assert.Nil(t, err)
   277  	giveback, executionErr3 = VerifyExecution(tx3, block, txWorldState3)
   278  	assert.Nil(t, executionErr3)
   279  	assert.False(t, giveback)
   280  	dependency3, err := txWorldState3.CheckAndUpdate()
   281  	assert.Nil(t, err)
   282  	assert.Equal(t, 1, len(dependency3))
   283  	assert.Equal(t, "2", dependency3[0])
   284  
   285  	acc3, err := block.worldState.GetOrCreateUserAccount(tx3.from.address)
   286  	assert.Equal(t, "1000000000000000001", acc3.Balance().String())
   287  	toacc3, err := block.worldState.GetOrCreateUserAccount(tx3.to.address)
   288  	assert.Equal(t, "1", toacc3.Balance().String())
   289  
   290  	assert.Nil(t, block.Seal())
   291  }
   292  
   293  func TestTransaction_VerifyExecution(t *testing.T) {
   294  	type testTx struct {
   295  		name            string
   296  		tx              *Transaction
   297  		fromBalance     *util.Uint128
   298  		gasUsed         *util.Uint128
   299  		wanted          error
   300  		afterBalance    *util.Uint128
   301  		toBalance       *util.Uint128
   302  		coinbaseBalance *util.Uint128
   303  		status          int
   304  		eventErr        string
   305  		giveback        bool
   306  	}
   307  	tests := []testTx{}
   308  
   309  	neb := testNeb(t)
   310  	bc := neb.chain
   311  
   312  	// 1NAS = 10^18
   313  	balance, _ := util.NewUint128FromString("1000000000000000000")
   314  	// normal tx
   315  	normalTx := mockNormalTransaction(bc.chainID, 0)
   316  	normalTx.value, _ = util.NewUint128FromInt(1000000)
   317  	gasConsume, err := normalTx.gasPrice.Mul(MinGasCountPerTransaction)
   318  	assert.Nil(t, err)
   319  	afterBalance, err := balance.Sub(gasConsume)
   320  	assert.Nil(t, err)
   321  	afterBalance, err = afterBalance.Sub(normalTx.value)
   322  	coinbaseBalance, err := normalTx.gasPrice.Mul(MinGasCountPerTransaction)
   323  	assert.Nil(t, err)
   324  	tests = append(tests, testTx{
   325  		name:            "normal tx",
   326  		tx:              normalTx,
   327  		fromBalance:     balance,
   328  		gasUsed:         MinGasCountPerTransaction,
   329  		afterBalance:    afterBalance,
   330  		toBalance:       normalTx.value,
   331  		coinbaseBalance: coinbaseBalance,
   332  		wanted:          nil,
   333  		eventErr:        "",
   334  		status:          1,
   335  		giveback:        false,
   336  	})
   337  
   338  	// contract deploy tx
   339  	deployTx := mockDeployTransaction(bc.chainID, 0)
   340  	deployTx.value = util.NewUint128()
   341  	gasUsed, _ := util.NewUint128FromInt(21203)
   342  	coinbaseBalance, err = deployTx.gasPrice.Mul(gasUsed)
   343  	assert.Nil(t, err)
   344  	balanceConsume, err := deployTx.gasPrice.Mul(gasUsed)
   345  	assert.Nil(t, err)
   346  	afterBalance, err = balance.Sub(balanceConsume)
   347  	assert.Nil(t, err)
   348  	tests = append(tests, testTx{
   349  		name:            "contract deploy tx",
   350  		tx:              deployTx,
   351  		fromBalance:     balance,
   352  		gasUsed:         gasUsed,
   353  		afterBalance:    afterBalance,
   354  		toBalance:       afterBalance,
   355  		coinbaseBalance: coinbaseBalance,
   356  		wanted:          nil,
   357  		eventErr:        "",
   358  		status:          1,
   359  		giveback:        false,
   360  	})
   361  
   362  	// contract call tx
   363  	callTx := mockCallTransaction(bc.chainID, 1, "totalSupply", "")
   364  	callTx.value = util.NewUint128()
   365  	gasUsed, _ = util.NewUint128FromInt(20096)
   366  	coinbaseBalance, err = callTx.gasPrice.Mul(gasUsed)
   367  	assert.Nil(t, err)
   368  	balanceConsume, err = callTx.gasPrice.Mul(gasUsed)
   369  	assert.Nil(t, err)
   370  	afterBalance, err = balance.Sub(balanceConsume)
   371  
   372  	tests = append(tests, testTx{
   373  		name:            "contract call tx",
   374  		tx:              callTx,
   375  		fromBalance:     balance,
   376  		gasUsed:         gasUsed,
   377  		afterBalance:    afterBalance,
   378  		toBalance:       callTx.value,
   379  		coinbaseBalance: coinbaseBalance,
   380  		wanted:          nil,
   381  		eventErr:        ErrContractCheckFailed.Error(),
   382  		status:          0,
   383  		giveback:        false,
   384  	})
   385  
   386  	// normal tx insufficient fromBalance before execution
   387  	insufficientBlanceTx := mockNormalTransaction(bc.chainID, 0)
   388  	insufficientBlanceTx.value = util.NewUint128()
   389  	tests = append(tests, testTx{
   390  		name:         "normal tx insufficient fromBalance",
   391  		tx:           insufficientBlanceTx,
   392  		fromBalance:  util.NewUint128(),
   393  		gasUsed:      util.Uint128Zero(),
   394  		afterBalance: util.NewUint128(),
   395  		toBalance:    util.NewUint128(),
   396  		wanted:       ErrInsufficientBalance,
   397  		status:       0,
   398  		giveback:     false,
   399  	})
   400  
   401  	// normal tx out of  gasLimit
   402  	outOfGasLimitTx := mockNormalTransaction(bc.chainID, 0)
   403  	outOfGasLimitTx.value = util.NewUint128()
   404  	outOfGasLimitTx.gasLimit, _ = util.NewUint128FromInt(1)
   405  	tests = append(tests, testTx{
   406  		name:         "normal tx out of gasLimit",
   407  		tx:           outOfGasLimitTx,
   408  		fromBalance:  balance,
   409  		gasUsed:      util.Uint128Zero(),
   410  		afterBalance: balance,
   411  		toBalance:    util.NewUint128(),
   412  		wanted:       ErrOutOfGasLimit,
   413  		status:       0,
   414  		giveback:     false,
   415  	})
   416  
   417  	// tx payload load err
   418  	payloadErrTx := mockDeployTransaction(bc.chainID, 0)
   419  	payloadErrTx.value = util.NewUint128()
   420  	payloadErrTx.data.Payload = []byte("0x00")
   421  	gasCountOfTxBase, err := payloadErrTx.GasCountOfTxBase()
   422  	assert.Nil(t, err)
   423  	coinbaseBalance, err = payloadErrTx.gasPrice.Mul(gasCountOfTxBase)
   424  	assert.Nil(t, err)
   425  	balanceConsume, err = payloadErrTx.gasPrice.Mul(gasCountOfTxBase)
   426  	assert.Nil(t, err)
   427  	afterBalance, err = balance.Sub(balanceConsume)
   428  	assert.Nil(t, err)
   429  	getUsed, err := payloadErrTx.GasCountOfTxBase()
   430  	assert.Nil(t, err)
   431  	tests = append(tests, testTx{
   432  		name:            "payload error tx",
   433  		tx:              payloadErrTx,
   434  		fromBalance:     balance,
   435  		gasUsed:         getUsed,
   436  		afterBalance:    afterBalance,
   437  		toBalance:       afterBalance,
   438  		coinbaseBalance: coinbaseBalance,
   439  		wanted:          nil,
   440  		eventErr:        "invalid argument(s)",
   441  		status:          0,
   442  		giveback:        false,
   443  	})
   444  
   445  	// tx execution err
   446  	executionErrTx := mockCallTransaction(bc.chainID, 0, "test", "")
   447  	executionErrTx.value = util.NewUint128()
   448  	result, err := bc.SimulateTransactionExecution(executionErrTx)
   449  	assert.Nil(t, err)
   450  	assert.Equal(t, ErrContractCheckFailed, result.Err)
   451  	coinbaseBalance, err = executionErrTx.gasPrice.Mul(result.GasUsed)
   452  	assert.Nil(t, err)
   453  	balanceConsume, err = executionErrTx.gasPrice.Mul(result.GasUsed)
   454  	assert.Nil(t, err)
   455  	afterBalance, err = balance.Sub(balanceConsume)
   456  	assert.Nil(t, err)
   457  
   458  	tests = append(tests, testTx{
   459  		name:            "execution err tx",
   460  		tx:              executionErrTx,
   461  		fromBalance:     balance,
   462  		gasUsed:         result.GasUsed,
   463  		afterBalance:    afterBalance,
   464  		toBalance:       util.NewUint128(),
   465  		coinbaseBalance: coinbaseBalance,
   466  		wanted:          nil,
   467  		eventErr:        ErrContractCheckFailed.Error(),
   468  		status:          0,
   469  		giveback:        false,
   470  	})
   471  
   472  	// tx execution insufficient fromBalance after execution
   473  	executionInsufficientBalanceTx := mockDeployTransaction(bc.chainID, 0)
   474  	executionInsufficientBalanceTx.value = balance
   475  	gasUsed, _ = util.NewUint128FromInt(21103)
   476  	coinbaseBalance, err = executionInsufficientBalanceTx.gasPrice.Mul(gasUsed)
   477  	assert.Nil(t, err)
   478  	balanceConsume, err = executionInsufficientBalanceTx.gasPrice.Mul(gasUsed)
   479  	assert.Nil(t, err)
   480  	afterBalance, err = balance.Sub(balanceConsume)
   481  	assert.Nil(t, err)
   482  	tests = append(tests, testTx{
   483  		name:            "execution insufficient fromBalance after execution tx",
   484  		tx:              executionInsufficientBalanceTx,
   485  		fromBalance:     balance,
   486  		gasUsed:         gasUsed,
   487  		afterBalance:    afterBalance,
   488  		toBalance:       afterBalance,
   489  		coinbaseBalance: coinbaseBalance,
   490  		wanted:          nil,
   491  		eventErr:        ErrInsufficientBalance.Error(),
   492  		status:          0,
   493  		giveback:        false,
   494  	})
   495  
   496  	// tx execution equal fromBalance after execution
   497  	executionEqualBalanceTx := mockDeployTransaction(bc.chainID, 0)
   498  	result, err = bc.SimulateTransactionExecution(executionEqualBalanceTx)
   499  	assert.Nil(t, err)
   500  	assert.Equal(t, ErrInsufficientBalance, result.Err)
   501  	executionEqualBalanceTx.gasLimit = result.GasUsed
   502  	t.Log("gasUsed:", result.GasUsed)
   503  	coinbaseBalance, err = executionInsufficientBalanceTx.gasPrice.Mul(result.GasUsed)
   504  	assert.Nil(t, err)
   505  	executionEqualBalanceTx.value = balance
   506  	gasCost, err := executionEqualBalanceTx.gasPrice.Mul(result.GasUsed)
   507  	assert.Nil(t, err)
   508  	fromBalance, err := gasCost.Add(balance)
   509  	assert.Nil(t, err)
   510  	tests = append(tests, testTx{
   511  		name:            "execution equal fromBalance after execution tx",
   512  		tx:              executionEqualBalanceTx,
   513  		fromBalance:     fromBalance,
   514  		gasUsed:         result.GasUsed,
   515  		afterBalance:    balance,
   516  		toBalance:       balance,
   517  		coinbaseBalance: coinbaseBalance,
   518  		wanted:          nil,
   519  		eventErr:        "",
   520  		status:          1,
   521  		giveback:        false,
   522  	})
   523  
   524  	ks := keystore.DefaultKS
   525  	for _, tt := range tests {
   526  		t.Run(tt.name, func(t *testing.T) {
   527  			key, _ := ks.GetUnlocked(tt.tx.from.String())
   528  			signature, _ := crypto.NewSignature(keystore.SECP256K1)
   529  			signature.InitSign(key.(keystore.PrivateKey))
   530  
   531  			err := tt.tx.Sign(signature)
   532  			assert.Nil(t, err)
   533  
   534  			block, err := bc.NewBlock(mockAddress())
   535  			block.Begin()
   536  			fromAcc, err := block.worldState.GetOrCreateUserAccount(tt.tx.from.address)
   537  			assert.Nil(t, err)
   538  			fromAcc.AddBalance(tt.fromBalance)
   539  			block.Commit()
   540  
   541  			block, err = bc.NewBlockFromParent(bc.tailBlock.header.coinbase, block)
   542  			assert.Nil(t, err)
   543  			block.Begin()
   544  
   545  			txWorldState, err := block.WorldState().Prepare(tt.tx.Hash().String())
   546  			assert.Nil(t, err)
   547  
   548  			giveback, executionErr := VerifyExecution(tt.tx, block, txWorldState)
   549  			assert.Equal(t, tt.wanted, executionErr)
   550  			assert.Equal(t, giveback, tt.giveback)
   551  			fromAcc, err = txWorldState.GetOrCreateUserAccount(tt.tx.from.address)
   552  			assert.Nil(t, err)
   553  			fmt.Println(fromAcc.Balance().String())
   554  
   555  			txWorldState.CheckAndUpdate()
   556  			assert.Nil(t, block.rewardCoinbaseForGas())
   557  			block.Commit()
   558  
   559  			fromAcc, err = block.worldState.GetOrCreateUserAccount(tt.tx.from.address)
   560  			assert.Nil(t, err)
   561  			toAcc, err := block.worldState.GetOrCreateUserAccount(tt.tx.to.address)
   562  			assert.Nil(t, err)
   563  			coinbaseAcc, err := block.worldState.GetOrCreateUserAccount(block.header.coinbase.address)
   564  			assert.Nil(t, err)
   565  
   566  			if tt.afterBalance != nil {
   567  				assert.Equal(t, tt.afterBalance.String(), fromAcc.Balance().String())
   568  			}
   569  			if tt.toBalance != nil {
   570  				assert.Equal(t, tt.toBalance, toAcc.Balance())
   571  			}
   572  			if tt.coinbaseBalance != nil {
   573  				coinbaseBalance, err := tt.coinbaseBalance.Add(BlockReward)
   574  				assert.Nil(t, err)
   575  				assert.Equal(t, coinbaseBalance, coinbaseAcc.Balance())
   576  			}
   577  
   578  			events, _ := block.worldState.FetchEvents(tt.tx.hash)
   579  
   580  			for _, v := range events {
   581  				if v.Topic == TopicTransactionExecutionResult {
   582  					txEvent := TransactionEvent{}
   583  					json.Unmarshal([]byte(v.Data), &txEvent)
   584  					status := int(txEvent.Status)
   585  					assert.Equal(t, tt.status, status)
   586  					assert.Equal(t, tt.eventErr, txEvent.Error)
   587  					assert.Equal(t, tt.gasUsed.String(), txEvent.GasUsed)
   588  					break
   589  				}
   590  			}
   591  		})
   592  	}
   593  }
   594  
   595  func TestTransaction_SimulateExecution(t *testing.T) {
   596  	type testCase struct {
   597  		name    string
   598  		tx      *Transaction
   599  		gasUsed *util.Uint128
   600  		result  string
   601  		wanted  error
   602  	}
   603  
   604  	tests := []testCase{}
   605  
   606  	neb := testNeb(t)
   607  	bc := neb.chain
   608  
   609  	normalTx := mockNormalTransaction(bc.chainID, 0)
   610  	normalTx.value, _ = util.NewUint128FromInt(1000000)
   611  	tests = append(tests, testCase{
   612  		name:    "normal tx",
   613  		tx:      normalTx,
   614  		gasUsed: MinGasCountPerTransaction,
   615  		result:  "",
   616  		wanted:  ErrInsufficientBalance,
   617  	})
   618  
   619  	deployTx := mockDeployTransaction(bc.chainID, 0)
   620  	deployTx.to = deployTx.from
   621  	deployTx.value = util.NewUint128()
   622  	gasUsed, _ := util.NewUint128FromInt(21203)
   623  	tests = append(tests, testCase{
   624  		name:    "contract deploy tx",
   625  		tx:      deployTx,
   626  		gasUsed: gasUsed,
   627  		result:  "",
   628  		wanted:  ErrInsufficientBalance,
   629  	})
   630  
   631  	// contract call tx
   632  	callTx := mockCallTransaction(bc.chainID, 1, "totalSupply", "")
   633  	callTx.value = util.NewUint128()
   634  	gasUsed, _ = util.NewUint128FromInt(20096)
   635  	tests = append(tests, testCase{
   636  		name:    "contract call tx",
   637  		tx:      callTx,
   638  		gasUsed: gasUsed,
   639  		result:  "",
   640  		wanted:  ErrContractCheckFailed,
   641  	})
   642  
   643  	for _, tt := range tests {
   644  		t.Run(tt.name, func(t *testing.T) {
   645  			block, err := bc.NewBlock(bc.tailBlock.header.coinbase)
   646  			assert.Nil(t, err)
   647  
   648  			fromAcc, err := block.worldState.GetOrCreateUserAccount(tt.tx.from.address)
   649  			assert.Nil(t, err)
   650  			fromBefore := fromAcc.Balance()
   651  
   652  			toAcc, err := block.worldState.GetOrCreateUserAccount(tt.tx.to.address)
   653  			assert.Nil(t, err)
   654  			toBefore := toAcc.Balance()
   655  
   656  			coinbaseAcc, err := block.worldState.GetOrCreateUserAccount(block.header.coinbase.address)
   657  			assert.Nil(t, err)
   658  			coinbaseBefore := coinbaseAcc.Balance()
   659  
   660  			result, err := tt.tx.simulateExecution(block)
   661  
   662  			assert.Equal(t, tt.wanted, result.Err)
   663  			assert.Equal(t, tt.result, result.Msg)
   664  			assert.Equal(t, tt.gasUsed, result.GasUsed)
   665  			assert.Nil(t, err)
   666  
   667  			fromAcc, err = block.worldState.GetOrCreateUserAccount(tt.tx.from.address)
   668  			assert.Nil(t, err)
   669  			assert.Equal(t, fromBefore, fromAcc.Balance())
   670  
   671  			toAcc, err = block.worldState.GetOrCreateUserAccount(tt.tx.to.address)
   672  			assert.Nil(t, err)
   673  			assert.Equal(t, toBefore, toAcc.Balance())
   674  
   675  			coinbaseAcc, err = block.worldState.GetOrCreateUserAccount(block.header.coinbase.address)
   676  			assert.Nil(t, err)
   677  			assert.Equal(t, coinbaseBefore, coinbaseAcc.Balance())
   678  
   679  			block.Seal()
   680  		})
   681  	}
   682  }
   683  
   684  func TestDeployAndCall(t *testing.T) {
   685  	neb := testNeb(t)
   686  	bc := neb.chain
   687  
   688  	coinbase := mockAddress()
   689  	from := mockAddress()
   690  	balance, _ := util.NewUint128FromString("1000000000000000000")
   691  
   692  	ks := keystore.DefaultKS
   693  	key, _ := ks.GetUnlocked(from.String())
   694  	signature, _ := crypto.NewSignature(keystore.SECP256K1)
   695  	signature.InitSign(key.(keystore.PrivateKey))
   696  
   697  	block, err := bc.NewBlock(coinbase)
   698  	fromAcc, err := block.worldState.GetOrCreateUserAccount(from.address)
   699  	assert.Nil(t, err)
   700  	fromAcc.AddBalance(balance)
   701  	block.Commit()
   702  
   703  	// contract deploy tx
   704  	deployTx := mockDeployTransaction(bc.chainID, 0)
   705  	deployTx.from = from
   706  	deployTx.to = from
   707  	deployTx.value = util.NewUint128()
   708  	deployTx.Sign(signature)
   709  
   710  	// contract call tx
   711  	callTx := mockCallTransaction(bc.chainID, 1, "totalSupply", "")
   712  	callTx.from = from
   713  	callTx.to, _ = deployTx.GenerateContractAddress()
   714  	callTx.value = util.NewUint128()
   715  	callTx.Sign(signature)
   716  
   717  	assert.Nil(t, err)
   718  
   719  	block, err = bc.NewBlockFromParent(bc.tailBlock.header.coinbase, block)
   720  	assert.Nil(t, err)
   721  
   722  	txWorldState, err := block.WorldState().Prepare(deployTx.Hash().String())
   723  	assert.Nil(t, err)
   724  	giveback, err := VerifyExecution(deployTx, block, txWorldState)
   725  	assert.False(t, giveback)
   726  	assert.Nil(t, err)
   727  	giveback, err = AcceptTransaction(deployTx, txWorldState)
   728  	assert.False(t, giveback)
   729  	assert.Nil(t, err)
   730  	_, err = txWorldState.CheckAndUpdate()
   731  	assert.Nil(t, err)
   732  
   733  	deployEvents, _ := block.worldState.FetchEvents(deployTx.Hash())
   734  	assert.Equal(t, len(deployEvents), 1)
   735  	event := deployEvents[0]
   736  	if event.Topic == TopicTransactionExecutionResult {
   737  		txEvent := TransactionEvent{}
   738  		json.Unmarshal([]byte(event.Data), &txEvent)
   739  		status := int(txEvent.Status)
   740  		assert.Equal(t, status, TxExecutionSuccess)
   741  	}
   742  
   743  	txWorldState, err = block.WorldState().Prepare(callTx.Hash().String())
   744  	assert.Nil(t, err)
   745  	giveback, err = VerifyExecution(callTx, block, txWorldState)
   746  	assert.False(t, giveback)
   747  	assert.Nil(t, err)
   748  	giveback, err = AcceptTransaction(callTx, txWorldState)
   749  	assert.False(t, giveback)
   750  	assert.Nil(t, err)
   751  	_, err = txWorldState.CheckAndUpdate()
   752  	assert.Nil(t, err)
   753  
   754  	block.Commit()
   755  
   756  	callEvents, _ := block.worldState.FetchEvents(callTx.Hash())
   757  	assert.Equal(t, len(callEvents), 1)
   758  	event = callEvents[0]
   759  	if event.Topic == TopicTransactionExecutionResult {
   760  		txEvent := TransactionEvent{}
   761  		json.Unmarshal([]byte(event.Data), &txEvent)
   762  		status := int(txEvent.Status)
   763  		assert.Equal(t, status, TxExecutionSuccess)
   764  	}
   765  }
   766  
   767  func Test1(t *testing.T) {
   768  	fmt.Println(len(hash.Sha3256([]byte("abc"))))
   769  }
   770  func TestTransactionString(t *testing.T) {
   771  	neb := testNeb(t)
   772  	bc := neb.chain
   773  
   774  	a := mockAddress()
   775  	b := mockAddress()
   776  
   777  	v, _ := util.NewUint128FromInt(1)
   778  	data := `{"Function":"donation","Args":"[\"d\"]"}", "type":"call"}`
   779  	tx1, _ := NewTransaction(bc.chainID, a, b, v, uint64(1), TxPayloadDeployType, []byte(data), TransactionGasPrice, TransactionMaxGas)
   780  	expectedOut := fmt.Sprintf(`{"chainID":100,"data":"{\"Function\":\"donation\",\"Args\":\"[\\\"d\\\"]\"}\", \"type\":\"call\"}","from":"%s","gaslimit":"50000000000","gasprice":"1000000","hash":"","nonce":1,"timestamp":%d,"to":"%s","type":"deploy","value":"1"}`, a, tx1.timestamp, b)
   781  
   782  	if tx1.String() == tx1.JSONString() {
   783  		t.Errorf("tx String() != tx.JsonString")
   784  	}
   785  
   786  	if tx1.JSONString() != expectedOut {
   787  		fmt.Println(tx1.JSONString())
   788  		fmt.Println(expectedOut)
   789  		t.Errorf("tx JsonString() is not working as xpected")
   790  	}
   791  }