github.com/theQRL/go-zond@v0.2.1/zond/tracers/api_test.go (about)

     1  // Copyright 2021 The go-ethereum Authors
     2  // This file is part of the go-ethereum library.
     3  //
     4  // The go-ethereum library is free software: you can redistribute it and/or modify
     5  // it under the terms of the GNU Lesser General Public License as published by
     6  // the Free Software Foundation, either version 3 of the License, or
     7  // (at your option) any later version.
     8  //
     9  // The go-ethereum library is distributed in the hope that it will be useful,
    10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    12  // GNU Lesser General Public License for more details.
    13  //
    14  // You should have received a copy of the GNU Lesser General Public License
    15  // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  package tracers
    18  
    19  import (
    20  	"context"
    21  	"encoding/json"
    22  	"errors"
    23  	"fmt"
    24  	"math/big"
    25  	"reflect"
    26  	"slices"
    27  	"sync/atomic"
    28  	"testing"
    29  	"time"
    30  
    31  	"github.com/theQRL/go-qrllib/dilithium"
    32  	"github.com/theQRL/go-zond/common"
    33  	"github.com/theQRL/go-zond/common/hexutil"
    34  	"github.com/theQRL/go-zond/consensus"
    35  	"github.com/theQRL/go-zond/consensus/beacon"
    36  	"github.com/theQRL/go-zond/core"
    37  	"github.com/theQRL/go-zond/core/rawdb"
    38  	"github.com/theQRL/go-zond/core/state"
    39  	"github.com/theQRL/go-zond/core/types"
    40  	"github.com/theQRL/go-zond/core/vm"
    41  	"github.com/theQRL/go-zond/crypto"
    42  	"github.com/theQRL/go-zond/internal/zondapi"
    43  	"github.com/theQRL/go-zond/params"
    44  	"github.com/theQRL/go-zond/rpc"
    45  	"github.com/theQRL/go-zond/zond/tracers/logger"
    46  	"github.com/theQRL/go-zond/zonddb"
    47  )
    48  
    49  var (
    50  	errStateNotFound = errors.New("state not found")
    51  	errBlockNotFound = errors.New("block not found")
    52  )
    53  
    54  type testBackend struct {
    55  	chainConfig *params.ChainConfig
    56  	engine      consensus.Engine
    57  	chaindb     zonddb.Database
    58  	chain       *core.BlockChain
    59  
    60  	refHook func() // Hook is invoked when the requested state is referenced
    61  	relHook func() // Hook is invoked when the requested state is released
    62  }
    63  
    64  // testBackend creates a new test backend. OBS: After test is done, teardown must be
    65  // invoked in order to release associated resources.
    66  func newTestBackend(t *testing.T, n int, gspec *core.Genesis, generator func(i int, b *core.BlockGen)) *testBackend {
    67  	backend := &testBackend{
    68  		chainConfig: gspec.Config,
    69  		engine:      beacon.NewFaker(),
    70  		chaindb:     rawdb.NewMemoryDatabase(),
    71  	}
    72  	// Generate blocks for testing
    73  	_, blocks, _ := core.GenerateChainWithGenesis(gspec, backend.engine, n, generator)
    74  
    75  	// Import the canonical chain
    76  	cacheConfig := &core.CacheConfig{
    77  		TrieCleanLimit:    256,
    78  		TrieDirtyLimit:    256,
    79  		TrieTimeLimit:     5 * time.Minute,
    80  		SnapshotLimit:     0,
    81  		TrieDirtyDisabled: true, // Archive mode
    82  	}
    83  	chain, err := core.NewBlockChain(backend.chaindb, cacheConfig, gspec, backend.engine, vm.Config{}, nil)
    84  	if err != nil {
    85  		t.Fatalf("failed to create tester chain: %v", err)
    86  	}
    87  	if n, err := chain.InsertChain(blocks); err != nil {
    88  		t.Fatalf("block %d: failed to insert into chain: %v", n, err)
    89  	}
    90  	backend.chain = chain
    91  	return backend
    92  }
    93  
    94  func (b *testBackend) HeaderByHash(ctx context.Context, hash common.Hash) (*types.Header, error) {
    95  	return b.chain.GetHeaderByHash(hash), nil
    96  }
    97  
    98  func (b *testBackend) HeaderByNumber(ctx context.Context, number rpc.BlockNumber) (*types.Header, error) {
    99  	if number == rpc.PendingBlockNumber || number == rpc.LatestBlockNumber {
   100  		return b.chain.CurrentHeader(), nil
   101  	}
   102  	return b.chain.GetHeaderByNumber(uint64(number)), nil
   103  }
   104  
   105  func (b *testBackend) BlockByHash(ctx context.Context, hash common.Hash) (*types.Block, error) {
   106  	return b.chain.GetBlockByHash(hash), nil
   107  }
   108  
   109  func (b *testBackend) BlockByNumber(ctx context.Context, number rpc.BlockNumber) (*types.Block, error) {
   110  	if number == rpc.PendingBlockNumber || number == rpc.LatestBlockNumber {
   111  		return b.chain.GetBlockByNumber(b.chain.CurrentBlock().Number.Uint64()), nil
   112  	}
   113  	return b.chain.GetBlockByNumber(uint64(number)), nil
   114  }
   115  
   116  func (b *testBackend) GetTransaction(ctx context.Context, txHash common.Hash) (*types.Transaction, common.Hash, uint64, uint64, error) {
   117  	tx, hash, blockNumber, index := rawdb.ReadTransaction(b.chaindb, txHash)
   118  	return tx, hash, blockNumber, index, nil
   119  }
   120  
   121  func (b *testBackend) RPCGasCap() uint64 {
   122  	return 25000000
   123  }
   124  
   125  func (b *testBackend) ChainConfig() *params.ChainConfig {
   126  	return b.chainConfig
   127  }
   128  
   129  func (b *testBackend) Engine() consensus.Engine {
   130  	return b.engine
   131  }
   132  
   133  func (b *testBackend) ChainDb() zonddb.Database {
   134  	return b.chaindb
   135  }
   136  
   137  // teardown releases the associated resources.
   138  func (b *testBackend) teardown() {
   139  	b.chain.Stop()
   140  }
   141  
   142  func (b *testBackend) StateAtBlock(ctx context.Context, block *types.Block, reexec uint64, base *state.StateDB, readOnly bool, preferDisk bool) (*state.StateDB, StateReleaseFunc, error) {
   143  	statedb, err := b.chain.StateAt(block.Root())
   144  	if err != nil {
   145  		return nil, nil, errStateNotFound
   146  	}
   147  	if b.refHook != nil {
   148  		b.refHook()
   149  	}
   150  	release := func() {
   151  		if b.relHook != nil {
   152  			b.relHook()
   153  		}
   154  	}
   155  	return statedb, release, nil
   156  }
   157  
   158  func (b *testBackend) StateAtTransaction(ctx context.Context, block *types.Block, txIndex int, reexec uint64) (*core.Message, vm.BlockContext, *state.StateDB, StateReleaseFunc, error) {
   159  	parent := b.chain.GetBlock(block.ParentHash(), block.NumberU64()-1)
   160  	if parent == nil {
   161  		return nil, vm.BlockContext{}, nil, nil, errBlockNotFound
   162  	}
   163  	statedb, release, err := b.StateAtBlock(ctx, parent, reexec, nil, true, false)
   164  	if err != nil {
   165  		return nil, vm.BlockContext{}, nil, nil, errStateNotFound
   166  	}
   167  	if txIndex == 0 && len(block.Transactions()) == 0 {
   168  		return nil, vm.BlockContext{}, statedb, release, nil
   169  	}
   170  	// Recompute transactions up to the target index.
   171  	signer := types.MakeSigner(b.chainConfig)
   172  	for idx, tx := range block.Transactions() {
   173  		msg, _ := core.TransactionToMessage(tx, signer, block.BaseFee())
   174  		txContext := core.NewZVMTxContext(msg)
   175  		context := core.NewZVMBlockContext(block.Header(), b.chain, nil)
   176  		if idx == txIndex {
   177  			return msg, context, statedb, release, nil
   178  		}
   179  		vmenv := vm.NewZVM(context, txContext, statedb, b.chainConfig, vm.Config{})
   180  		if _, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(tx.Gas())); err != nil {
   181  			return nil, vm.BlockContext{}, nil, nil, fmt.Errorf("transaction %#x failed: %v", tx.Hash(), err)
   182  		}
   183  		statedb.Finalise(true)
   184  	}
   185  	return nil, vm.BlockContext{}, nil, nil, fmt.Errorf("transaction index %d out of range for block %#x", txIndex, block.Hash())
   186  }
   187  
   188  func TestTraceCall(t *testing.T) {
   189  	t.Parallel()
   190  
   191  	// Initialize test accounts
   192  	accounts := newAccounts(3)
   193  	genesis := &core.Genesis{
   194  		Config: params.TestChainConfig,
   195  		Alloc: core.GenesisAlloc{
   196  			accounts[0].addr: {Balance: big.NewInt(params.Ether)},
   197  			accounts[1].addr: {Balance: big.NewInt(params.Ether)},
   198  			accounts[2].addr: {Balance: big.NewInt(params.Ether)},
   199  		},
   200  	}
   201  	genBlocks := 10
   202  	signer := types.ShanghaiSigner{ChainId: big.NewInt(1)}
   203  	backend := newTestBackend(t, genBlocks, genesis, func(i int, b *core.BlockGen) {
   204  		// Transfer from account[0] to account[1]
   205  		//    value: 1000 wei
   206  		//    fee:   0 wei
   207  		tx := types.NewTx(&types.DynamicFeeTx{
   208  			Nonce:     uint64(i),
   209  			To:        &accounts[1].addr,
   210  			Value:     big.NewInt(1000),
   211  			Gas:       params.TxGas,
   212  			GasFeeCap: b.BaseFee(),
   213  			Data:      nil,
   214  		})
   215  		signedTx, _ := types.SignTx(tx, signer, accounts[0].key)
   216  		b.AddTx(signedTx)
   217  	})
   218  	defer backend.teardown()
   219  	api := NewAPI(backend)
   220  	var testSuite = []struct {
   221  		blockNumber rpc.BlockNumber
   222  		call        zondapi.TransactionArgs
   223  		config      *TraceCallConfig
   224  		expectErr   error
   225  		expect      string
   226  	}{
   227  		// Standard JSON trace upon the genesis, plain transfer.
   228  		{
   229  			blockNumber: rpc.BlockNumber(0),
   230  			call: zondapi.TransactionArgs{
   231  				From:  &accounts[0].addr,
   232  				To:    &accounts[1].addr,
   233  				Value: (*hexutil.Big)(big.NewInt(1000)),
   234  			},
   235  			config:    nil,
   236  			expectErr: nil,
   237  			expect:    `{"gas":21000,"failed":false,"returnValue":"","structLogs":[]}`,
   238  		},
   239  		// Standard JSON trace upon the head, plain transfer.
   240  		{
   241  			blockNumber: rpc.BlockNumber(genBlocks),
   242  			call: zondapi.TransactionArgs{
   243  				From:  &accounts[0].addr,
   244  				To:    &accounts[1].addr,
   245  				Value: (*hexutil.Big)(big.NewInt(1000)),
   246  			},
   247  			config:    nil,
   248  			expectErr: nil,
   249  			expect:    `{"gas":21000,"failed":false,"returnValue":"","structLogs":[]}`,
   250  		},
   251  		// Standard JSON trace upon the non-existent block, error expects
   252  		{
   253  			blockNumber: rpc.BlockNumber(genBlocks + 1),
   254  			call: zondapi.TransactionArgs{
   255  				From:  &accounts[0].addr,
   256  				To:    &accounts[1].addr,
   257  				Value: (*hexutil.Big)(big.NewInt(1000)),
   258  			},
   259  			config:    nil,
   260  			expectErr: fmt.Errorf("block #%d not found", genBlocks+1),
   261  			//expect:    nil,
   262  		},
   263  		// Standard JSON trace upon the latest block
   264  		{
   265  			blockNumber: rpc.LatestBlockNumber,
   266  			call: zondapi.TransactionArgs{
   267  				From:  &accounts[0].addr,
   268  				To:    &accounts[1].addr,
   269  				Value: (*hexutil.Big)(big.NewInt(1000)),
   270  			},
   271  			config:    nil,
   272  			expectErr: nil,
   273  			expect:    `{"gas":21000,"failed":false,"returnValue":"","structLogs":[]}`,
   274  		},
   275  		// Tracing on 'pending' should fail:
   276  		{
   277  			blockNumber: rpc.PendingBlockNumber,
   278  			call: zondapi.TransactionArgs{
   279  				From:  &accounts[0].addr,
   280  				To:    &accounts[1].addr,
   281  				Value: (*hexutil.Big)(big.NewInt(1000)),
   282  			},
   283  			config:    nil,
   284  			expectErr: errors.New("tracing on top of pending is not supported"),
   285  		},
   286  		{
   287  			blockNumber: rpc.LatestBlockNumber,
   288  			call: zondapi.TransactionArgs{
   289  				From:  &accounts[0].addr,
   290  				Input: &hexutil.Bytes{0x43}, // blocknumber
   291  			},
   292  			config: &TraceCallConfig{
   293  				BlockOverrides: &zondapi.BlockOverrides{Number: (*hexutil.Big)(big.NewInt(0x1337))},
   294  			},
   295  			expectErr: nil,
   296  			expect: ` {"gas":53020,"failed":false,"returnValue":"","structLogs":[
   297  				{"pc":0,"op":"NUMBER","gas":24946982,"gasCost":2,"depth":1,"stack":[]},
   298  				{"pc":1,"op":"STOP","gas":24946980,"gasCost":0,"depth":1,"stack":["0x1337"]}]}`,
   299  		},
   300  	}
   301  	for i, testspec := range testSuite {
   302  		result, err := api.TraceCall(context.Background(), testspec.call, rpc.BlockNumberOrHash{BlockNumber: &testspec.blockNumber}, testspec.config)
   303  		if testspec.expectErr != nil {
   304  			if err == nil {
   305  				t.Errorf("test %d: expect error %v, got nothing", i, testspec.expectErr)
   306  				continue
   307  			}
   308  			if !reflect.DeepEqual(err, testspec.expectErr) {
   309  				t.Errorf("test %d: error mismatch, want %v, git %v", i, testspec.expectErr, err)
   310  			}
   311  		} else {
   312  			if err != nil {
   313  				t.Errorf("test %d: expect no error, got %v", i, err)
   314  				continue
   315  			}
   316  			var have *logger.ExecutionResult
   317  			if err := json.Unmarshal(result.(json.RawMessage), &have); err != nil {
   318  				t.Errorf("test %d: failed to unmarshal result %v", i, err)
   319  			}
   320  			var want *logger.ExecutionResult
   321  			if err := json.Unmarshal([]byte(testspec.expect), &want); err != nil {
   322  				t.Errorf("test %d: failed to unmarshal result %v", i, err)
   323  			}
   324  			if !reflect.DeepEqual(have, want) {
   325  				t.Errorf("test %d: result mismatch, want %v, got %v", i, testspec.expect, string(result.(json.RawMessage)))
   326  			}
   327  		}
   328  	}
   329  }
   330  
   331  func TestTraceTransaction(t *testing.T) {
   332  	t.Parallel()
   333  
   334  	// Initialize test accounts
   335  	accounts := newAccounts(2)
   336  	genesis := &core.Genesis{
   337  		Config: params.TestChainConfig,
   338  		Alloc: core.GenesisAlloc{
   339  			accounts[0].addr: {Balance: big.NewInt(params.Ether)},
   340  			accounts[1].addr: {Balance: big.NewInt(params.Ether)},
   341  		},
   342  	}
   343  	target := common.Hash{}
   344  	signer := types.ShanghaiSigner{ChainId: big.NewInt(1)}
   345  	backend := newTestBackend(t, 1, genesis, func(i int, b *core.BlockGen) {
   346  		// Transfer from account[0] to account[1]
   347  		//    value: 1000 wei
   348  		//    fee:   0 wei
   349  		tx := types.NewTx(&types.DynamicFeeTx{
   350  			Nonce:     uint64(i),
   351  			To:        &accounts[1].addr,
   352  			Value:     big.NewInt(1000),
   353  			Gas:       params.TxGas,
   354  			GasFeeCap: b.BaseFee(),
   355  			Data:      nil,
   356  		})
   357  		signedTx, _ := types.SignTx(tx, signer, accounts[0].key)
   358  		b.AddTx(signedTx)
   359  		target = signedTx.Hash()
   360  	})
   361  	defer backend.chain.Stop()
   362  	api := NewAPI(backend)
   363  	result, err := api.TraceTransaction(context.Background(), target, nil)
   364  	if err != nil {
   365  		t.Errorf("Failed to trace transaction %v", err)
   366  	}
   367  	var have *logger.ExecutionResult
   368  	if err := json.Unmarshal(result.(json.RawMessage), &have); err != nil {
   369  		t.Errorf("failed to unmarshal result %v", err)
   370  	}
   371  	if !reflect.DeepEqual(have, &logger.ExecutionResult{
   372  		Gas:         params.TxGas,
   373  		Failed:      false,
   374  		ReturnValue: "",
   375  		StructLogs:  []logger.StructLogRes{},
   376  	}) {
   377  		t.Error("Transaction tracing result is different")
   378  	}
   379  
   380  	// Test non-existent transaction
   381  	_, err = api.TraceTransaction(context.Background(), common.Hash{42}, nil)
   382  	if !errors.Is(err, errTxNotFound) {
   383  		t.Fatalf("want %v, have %v", errTxNotFound, err)
   384  	}
   385  }
   386  
   387  func TestTraceBlock(t *testing.T) {
   388  	t.Parallel()
   389  
   390  	// Initialize test accounts
   391  	accounts := newAccounts(3)
   392  	genesis := &core.Genesis{
   393  		Config: params.TestChainConfig,
   394  		Alloc: core.GenesisAlloc{
   395  			accounts[0].addr: {Balance: big.NewInt(params.Ether)},
   396  			accounts[1].addr: {Balance: big.NewInt(params.Ether)},
   397  			accounts[2].addr: {Balance: big.NewInt(params.Ether)},
   398  		},
   399  	}
   400  	genBlocks := 10
   401  	signer := types.ShanghaiSigner{ChainId: big.NewInt(1)}
   402  	var txHash common.Hash
   403  	backend := newTestBackend(t, genBlocks, genesis, func(i int, b *core.BlockGen) {
   404  		// Transfer from account[0] to account[1]
   405  		//    value: 1000 wei
   406  		//    fee:   0 wei
   407  		tx := types.NewTx(&types.DynamicFeeTx{
   408  			Nonce:     uint64(i),
   409  			To:        &accounts[1].addr,
   410  			Value:     big.NewInt(1000),
   411  			Gas:       params.TxGas,
   412  			GasFeeCap: b.BaseFee(),
   413  			Data:      nil,
   414  		})
   415  		signedTx, _ := types.SignTx(tx, signer, accounts[0].key)
   416  		b.AddTx(signedTx)
   417  		txHash = signedTx.Hash()
   418  	})
   419  	defer backend.chain.Stop()
   420  	api := NewAPI(backend)
   421  
   422  	var testSuite = []struct {
   423  		blockNumber rpc.BlockNumber
   424  		config      *TraceConfig
   425  		want        string
   426  		expectErr   error
   427  	}{
   428  		// Trace genesis block, expect error
   429  		{
   430  			blockNumber: rpc.BlockNumber(0),
   431  			expectErr:   errors.New("genesis is not traceable"),
   432  		},
   433  		// Trace head block
   434  		{
   435  			blockNumber: rpc.BlockNumber(genBlocks),
   436  			want:        fmt.Sprintf(`[{"txHash":"%v","result":{"gas":21000,"failed":false,"returnValue":"","structLogs":[]}}]`, txHash),
   437  		},
   438  		// Trace non-existent block
   439  		{
   440  			blockNumber: rpc.BlockNumber(genBlocks + 1),
   441  			expectErr:   fmt.Errorf("block #%d not found", genBlocks+1),
   442  		},
   443  		// Trace latest block
   444  		{
   445  			blockNumber: rpc.LatestBlockNumber,
   446  			want:        fmt.Sprintf(`[{"txHash":"%v","result":{"gas":21000,"failed":false,"returnValue":"","structLogs":[]}}]`, txHash),
   447  		},
   448  		// Trace pending block
   449  		{
   450  			blockNumber: rpc.PendingBlockNumber,
   451  			want:        fmt.Sprintf(`[{"txHash":"%v","result":{"gas":21000,"failed":false,"returnValue":"","structLogs":[]}}]`, txHash),
   452  		},
   453  	}
   454  	for i, tc := range testSuite {
   455  		result, err := api.TraceBlockByNumber(context.Background(), tc.blockNumber, tc.config)
   456  		if tc.expectErr != nil {
   457  			if err == nil {
   458  				t.Errorf("test %d, want error %v", i, tc.expectErr)
   459  				continue
   460  			}
   461  			if !reflect.DeepEqual(err, tc.expectErr) {
   462  				t.Errorf("test %d: error mismatch, want %v, get %v", i, tc.expectErr, err)
   463  			}
   464  			continue
   465  		}
   466  		if err != nil {
   467  			t.Errorf("test %d, want no error, have %v", i, err)
   468  			continue
   469  		}
   470  		have, _ := json.Marshal(result)
   471  		want := tc.want
   472  		if string(have) != want {
   473  			t.Errorf("test %d, result mismatch, have\n%v\n, want\n%v\n", i, string(have), want)
   474  		}
   475  	}
   476  }
   477  
   478  func TestTracingWithOverrides(t *testing.T) {
   479  	t.Parallel()
   480  	// Initialize test accounts
   481  	accounts := newAccounts(3)
   482  	storageAccount := common.Address{0x13, 37}
   483  	genesis := &core.Genesis{
   484  		Config: params.TestChainConfig,
   485  		Alloc: core.GenesisAlloc{
   486  			accounts[0].addr: {Balance: big.NewInt(params.Ether)},
   487  			accounts[1].addr: {Balance: big.NewInt(params.Ether)},
   488  			accounts[2].addr: {Balance: big.NewInt(params.Ether)},
   489  			// An account with existing storage
   490  			storageAccount: {
   491  				Balance: new(big.Int),
   492  				Storage: map[common.Hash]common.Hash{
   493  					common.HexToHash("0x03"): common.HexToHash("0x33"),
   494  					common.HexToHash("0x04"): common.HexToHash("0x44"),
   495  				},
   496  			},
   497  		},
   498  	}
   499  	genBlocks := 10
   500  	signer := types.ShanghaiSigner{ChainId: big.NewInt(1)}
   501  	backend := newTestBackend(t, genBlocks, genesis, func(i int, b *core.BlockGen) {
   502  		// Transfer from account[0] to account[1]
   503  		//    value: 1000 wei
   504  		//    fee:   0 wei
   505  		tx := types.NewTx(&types.DynamicFeeTx{
   506  			Nonce:     uint64(i),
   507  			To:        &accounts[1].addr,
   508  			Value:     big.NewInt(1000),
   509  			Gas:       params.TxGas,
   510  			GasFeeCap: b.BaseFee(),
   511  			Data:      nil,
   512  		})
   513  		signedTx, _ := types.SignTx(tx, signer, accounts[0].key)
   514  		b.AddTx(signedTx)
   515  	})
   516  	defer backend.chain.Stop()
   517  	api := NewAPI(backend)
   518  	randomAccounts := newAccounts(3)
   519  	type res struct {
   520  		Gas         int
   521  		Failed      bool
   522  		ReturnValue string
   523  	}
   524  	var testSuite = []struct {
   525  		blockNumber rpc.BlockNumber
   526  		call        zondapi.TransactionArgs
   527  		config      *TraceCallConfig
   528  		expectErr   error
   529  		want        string
   530  	}{
   531  		// Call which can only succeed if state is state overridden
   532  		{
   533  			blockNumber: rpc.LatestBlockNumber,
   534  			call: zondapi.TransactionArgs{
   535  				From:  &randomAccounts[0].addr,
   536  				To:    &randomAccounts[1].addr,
   537  				Value: (*hexutil.Big)(big.NewInt(1000)),
   538  			},
   539  			config: &TraceCallConfig{
   540  				StateOverrides: &zondapi.StateOverride{
   541  					randomAccounts[0].addr: zondapi.OverrideAccount{Balance: newRPCBalance(new(big.Int).Mul(big.NewInt(1), big.NewInt(params.Ether)))},
   542  				},
   543  			},
   544  			want: `{"gas":21000,"failed":false,"returnValue":""}`,
   545  		},
   546  		// Invalid call without state overriding
   547  		{
   548  			blockNumber: rpc.LatestBlockNumber,
   549  			call: zondapi.TransactionArgs{
   550  				From:  &randomAccounts[0].addr,
   551  				To:    &randomAccounts[1].addr,
   552  				Value: (*hexutil.Big)(big.NewInt(1000)),
   553  			},
   554  			config:    &TraceCallConfig{},
   555  			expectErr: core.ErrInsufficientFunds,
   556  		},
   557  		// Successful simple contract call
   558  		//
   559  		// // SPDX-License-Identifier: GPL-3.0
   560  		// // TODO(now.youtrack.cloud/issue/TGZ-30)
   561  		//  pragma hyperion >=0.7.0 <0.8.0;
   562  		//
   563  		//  /**
   564  		//   * @title Storage
   565  		//   * @dev Store & retrieve value in a variable
   566  		//   */
   567  		//  contract Storage {
   568  		//      uint256 public number;
   569  		//      constructor() {
   570  		//          number = block.number;
   571  		//      }
   572  		//  }
   573  		{
   574  			blockNumber: rpc.LatestBlockNumber,
   575  			call: zondapi.TransactionArgs{
   576  				From: &randomAccounts[0].addr,
   577  				To:   &randomAccounts[2].addr,
   578  				Data: newRPCBytes(common.Hex2Bytes("8381f58a")), // call number()
   579  			},
   580  			config: &TraceCallConfig{
   581  				//Tracer: &tracer,
   582  				StateOverrides: &zondapi.StateOverride{
   583  					randomAccounts[2].addr: zondapi.OverrideAccount{
   584  						Code:      newRPCBytes(common.Hex2Bytes("6080604052348015600f57600080fd5b506004361060285760003560e01c80638381f58a14602d575b600080fd5b60336049565b6040518082815260200191505060405180910390f35b6000548156fea2646970667358221220eab35ffa6ab2adfe380772a48b8ba78e82a1b820a18fcb6f59aa4efb20a5f60064736f6c63430007040033")),
   585  						StateDiff: newStates([]common.Hash{{}}, []common.Hash{common.BigToHash(big.NewInt(123))}),
   586  					},
   587  				},
   588  			},
   589  			want: `{"gas":23347,"failed":false,"returnValue":"000000000000000000000000000000000000000000000000000000000000007b"}`,
   590  		},
   591  		{ // Override blocknumber
   592  			blockNumber: rpc.LatestBlockNumber,
   593  			call: zondapi.TransactionArgs{
   594  				From: &accounts[0].addr,
   595  				// BLOCKNUMBER PUSH1 MSTORE
   596  				Input: newRPCBytes(common.Hex2Bytes("4360005260206000f3")),
   597  				//&hexutil.Bytes{0x43}, // blocknumber
   598  			},
   599  			config: &TraceCallConfig{
   600  				BlockOverrides: &zondapi.BlockOverrides{Number: (*hexutil.Big)(big.NewInt(0x1337))},
   601  			},
   602  			want: `{"gas":59539,"failed":false,"returnValue":"0000000000000000000000000000000000000000000000000000000000001337"}`,
   603  		},
   604  		{ // Override blocknumber, and query a blockhash
   605  			blockNumber: rpc.LatestBlockNumber,
   606  			call: zondapi.TransactionArgs{
   607  				From: &accounts[0].addr,
   608  				Input: &hexutil.Bytes{
   609  					0x60, 0x00, 0x40, // BLOCKHASH(0)
   610  					0x60, 0x00, 0x52, // STORE memory offset 0
   611  					0x61, 0x13, 0x36, 0x40, // BLOCKHASH(0x1336)
   612  					0x60, 0x20, 0x52, // STORE memory offset 32
   613  					0x61, 0x13, 0x37, 0x40, // BLOCKHASH(0x1337)
   614  					0x60, 0x40, 0x52, // STORE memory offset 64
   615  					0x60, 0x60, 0x60, 0x00, 0xf3, // RETURN (0-96)
   616  
   617  				}, // blocknumber
   618  			},
   619  			config: &TraceCallConfig{
   620  				BlockOverrides: &zondapi.BlockOverrides{Number: (*hexutil.Big)(big.NewInt(0x1337))},
   621  			},
   622  			want: `{"gas":72668,"failed":false,"returnValue":"000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"}`,
   623  		},
   624  		/*
   625  			// TODO(now.youtrack.cloud/issue/TGZ-30)
   626  			pragma hyperion =0.8.12;
   627  
   628  			contract Test {
   629  			    uint private x;
   630  
   631  			    function test2() external {
   632  			        x = 1337;
   633  			        revert();
   634  			    }
   635  
   636  			    function test() external returns (uint) {
   637  			        x = 1;
   638  			        try this.test2() {} catch (bytes memory) {}
   639  			        return x;
   640  			    }
   641  			}
   642  		*/
   643  		{ // First with only code override, not storage override
   644  			blockNumber: rpc.LatestBlockNumber,
   645  			call: zondapi.TransactionArgs{
   646  				From: &randomAccounts[0].addr,
   647  				To:   &randomAccounts[2].addr,
   648  				Data: newRPCBytes(common.Hex2Bytes("f8a8fd6d")), //
   649  			},
   650  			config: &TraceCallConfig{
   651  				StateOverrides: &zondapi.StateOverride{
   652  					randomAccounts[2].addr: zondapi.OverrideAccount{
   653  						Code: newRPCBytes(common.Hex2Bytes("6080604052348015600f57600080fd5b506004361060325760003560e01c806366e41cb7146037578063f8a8fd6d14603f575b600080fd5b603d6057565b005b60456062565b60405190815260200160405180910390f35b610539600090815580fd5b60006001600081905550306001600160a01b03166366e41cb76040518163ffffffff1660e01b8152600401600060405180830381600087803b15801560a657600080fd5b505af192505050801560b6575060015b60e9573d80801560e1576040519150601f19603f3d011682016040523d82523d6000602084013e60e6565b606091505b50505b506000549056fea26469706673582212205ce45de745a5308f713cb2f448589177ba5a442d1a2eff945afaa8915961b4d064736f6c634300080c0033")),
   654  					},
   655  				},
   656  			},
   657  			want: `{"gas":44100,"failed":false,"returnValue":"0000000000000000000000000000000000000000000000000000000000000001"}`,
   658  		},
   659  		{ // Same again, this time with storage override
   660  			blockNumber: rpc.LatestBlockNumber,
   661  			call: zondapi.TransactionArgs{
   662  				From: &randomAccounts[0].addr,
   663  				To:   &randomAccounts[2].addr,
   664  				Data: newRPCBytes(common.Hex2Bytes("f8a8fd6d")), //
   665  			},
   666  			config: &TraceCallConfig{
   667  				StateOverrides: &zondapi.StateOverride{
   668  					randomAccounts[2].addr: zondapi.OverrideAccount{
   669  						Code:  newRPCBytes(common.Hex2Bytes("6080604052348015600f57600080fd5b506004361060325760003560e01c806366e41cb7146037578063f8a8fd6d14603f575b600080fd5b603d6057565b005b60456062565b60405190815260200160405180910390f35b610539600090815580fd5b60006001600081905550306001600160a01b03166366e41cb76040518163ffffffff1660e01b8152600401600060405180830381600087803b15801560a657600080fd5b505af192505050801560b6575060015b60e9573d80801560e1576040519150601f19603f3d011682016040523d82523d6000602084013e60e6565b606091505b50505b506000549056fea26469706673582212205ce45de745a5308f713cb2f448589177ba5a442d1a2eff945afaa8915961b4d064736f6c634300080c0033")),
   670  						State: newStates([]common.Hash{{}}, []common.Hash{{}}),
   671  					},
   672  				},
   673  			},
   674  			want: `{"gas":44100,"failed":false,"returnValue":"0000000000000000000000000000000000000000000000000000000000000001"}`,
   675  		},
   676  		{ // No state override
   677  			blockNumber: rpc.LatestBlockNumber,
   678  			call: zondapi.TransactionArgs{
   679  				From: &randomAccounts[0].addr,
   680  				To:   &storageAccount,
   681  				Data: newRPCBytes(common.Hex2Bytes("f8a8fd6d")), //
   682  			},
   683  			config: &TraceCallConfig{
   684  				StateOverrides: &zondapi.StateOverride{
   685  					storageAccount: zondapi.OverrideAccount{
   686  						Code: newRPCBytes([]byte{
   687  							// SLOAD(3) + SLOAD(4) (which is 0x77)
   688  							byte(vm.PUSH1), 0x04,
   689  							byte(vm.SLOAD),
   690  							byte(vm.PUSH1), 0x03,
   691  							byte(vm.SLOAD),
   692  							byte(vm.ADD),
   693  							// 0x77 -> MSTORE(0)
   694  							byte(vm.PUSH1), 0x00,
   695  							byte(vm.MSTORE),
   696  							// RETURN (0, 32)
   697  							byte(vm.PUSH1), 32,
   698  							byte(vm.PUSH1), 00,
   699  							byte(vm.RETURN),
   700  						}),
   701  					},
   702  				},
   703  			},
   704  			want: `{"gas":25288,"failed":false,"returnValue":"0000000000000000000000000000000000000000000000000000000000000077"}`,
   705  		},
   706  		{ // Full state override
   707  			// The original storage is
   708  			// 3: 0x33
   709  			// 4: 0x44
   710  			// With a full override, where we set 3:0x11, the slot 4 should be
   711  			// removed. So SLOT(3)+SLOT(4) should be 0x11.
   712  			blockNumber: rpc.LatestBlockNumber,
   713  			call: zondapi.TransactionArgs{
   714  				From: &randomAccounts[0].addr,
   715  				To:   &storageAccount,
   716  				Data: newRPCBytes(common.Hex2Bytes("f8a8fd6d")), //
   717  			},
   718  			config: &TraceCallConfig{
   719  				StateOverrides: &zondapi.StateOverride{
   720  					storageAccount: zondapi.OverrideAccount{
   721  						Code: newRPCBytes([]byte{
   722  							// SLOAD(3) + SLOAD(4) (which is now 0x11 + 0x00)
   723  							byte(vm.PUSH1), 0x04,
   724  							byte(vm.SLOAD),
   725  							byte(vm.PUSH1), 0x03,
   726  							byte(vm.SLOAD),
   727  							byte(vm.ADD),
   728  							// 0x11 -> MSTORE(0)
   729  							byte(vm.PUSH1), 0x00,
   730  							byte(vm.MSTORE),
   731  							// RETURN (0, 32)
   732  							byte(vm.PUSH1), 32,
   733  							byte(vm.PUSH1), 00,
   734  							byte(vm.RETURN),
   735  						}),
   736  						State: newStates(
   737  							[]common.Hash{common.HexToHash("0x03")},
   738  							[]common.Hash{common.HexToHash("0x11")}),
   739  					},
   740  				},
   741  			},
   742  			want: `{"gas":25288,"failed":false,"returnValue":"0000000000000000000000000000000000000000000000000000000000000011"}`,
   743  		},
   744  		{ // Partial state override
   745  			// The original storage is
   746  			// 3: 0x33
   747  			// 4: 0x44
   748  			// With a partial override, where we set 3:0x11, the slot 4 as before.
   749  			// So SLOT(3)+SLOT(4) should be 0x55.
   750  			blockNumber: rpc.LatestBlockNumber,
   751  			call: zondapi.TransactionArgs{
   752  				From: &randomAccounts[0].addr,
   753  				To:   &storageAccount,
   754  				Data: newRPCBytes(common.Hex2Bytes("f8a8fd6d")), //
   755  			},
   756  			config: &TraceCallConfig{
   757  				StateOverrides: &zondapi.StateOverride{
   758  					storageAccount: zondapi.OverrideAccount{
   759  						Code: newRPCBytes([]byte{
   760  							// SLOAD(3) + SLOAD(4) (which is now 0x11 + 0x44)
   761  							byte(vm.PUSH1), 0x04,
   762  							byte(vm.SLOAD),
   763  							byte(vm.PUSH1), 0x03,
   764  							byte(vm.SLOAD),
   765  							byte(vm.ADD),
   766  							// 0x55 -> MSTORE(0)
   767  							byte(vm.PUSH1), 0x00,
   768  							byte(vm.MSTORE),
   769  							// RETURN (0, 32)
   770  							byte(vm.PUSH1), 32,
   771  							byte(vm.PUSH1), 00,
   772  							byte(vm.RETURN),
   773  						}),
   774  						StateDiff: &map[common.Hash]common.Hash{
   775  							common.HexToHash("0x03"): common.HexToHash("0x11"),
   776  						},
   777  					},
   778  				},
   779  			},
   780  			want: `{"gas":25288,"failed":false,"returnValue":"0000000000000000000000000000000000000000000000000000000000000055"}`,
   781  		},
   782  	}
   783  	for i, tc := range testSuite {
   784  		result, err := api.TraceCall(context.Background(), tc.call, rpc.BlockNumberOrHash{BlockNumber: &tc.blockNumber}, tc.config)
   785  		if tc.expectErr != nil {
   786  			if err == nil {
   787  				t.Errorf("test %d: want error %v, have nothing", i, tc.expectErr)
   788  				continue
   789  			}
   790  			if !errors.Is(err, tc.expectErr) {
   791  				t.Errorf("test %d: error mismatch, want %v, have %v", i, tc.expectErr, err)
   792  			}
   793  			continue
   794  		}
   795  		if err != nil {
   796  			t.Errorf("test %d: want no error, have %v", i, err)
   797  			continue
   798  		}
   799  		// Turn result into res-struct
   800  		var (
   801  			have res
   802  			want res
   803  		)
   804  		resBytes, _ := json.Marshal(result)
   805  		json.Unmarshal(resBytes, &have)
   806  		json.Unmarshal([]byte(tc.want), &want)
   807  		if !reflect.DeepEqual(have, want) {
   808  			t.Logf("result: %v\n", string(resBytes))
   809  			t.Errorf("test %d, result mismatch, have\n%v\n, want\n%v\n", i, have, want)
   810  		}
   811  	}
   812  }
   813  
   814  type Account struct {
   815  	key  *dilithium.Dilithium
   816  	addr common.Address
   817  }
   818  
   819  func newAccounts(n int) (accounts []Account) {
   820  	for i := 0; i < n; i++ {
   821  		key, _ := crypto.GenerateDilithiumKey()
   822  		addr := key.GetAddress()
   823  		accounts = append(accounts, Account{key: key, addr: addr})
   824  	}
   825  	slices.SortFunc(accounts, func(a, b Account) int { return a.addr.Cmp(b.addr) })
   826  	return accounts
   827  }
   828  
   829  func newRPCBalance(balance *big.Int) **hexutil.Big {
   830  	rpcBalance := (*hexutil.Big)(balance)
   831  	return &rpcBalance
   832  }
   833  
   834  func newRPCBytes(bytes []byte) *hexutil.Bytes {
   835  	rpcBytes := hexutil.Bytes(bytes)
   836  	return &rpcBytes
   837  }
   838  
   839  func newStates(keys []common.Hash, vals []common.Hash) *map[common.Hash]common.Hash {
   840  	if len(keys) != len(vals) {
   841  		panic("invalid input")
   842  	}
   843  	m := make(map[common.Hash]common.Hash)
   844  	for i := 0; i < len(keys); i++ {
   845  		m[keys[i]] = vals[i]
   846  	}
   847  	return &m
   848  }
   849  
   850  func TestTraceChain(t *testing.T) {
   851  	// Initialize test accounts
   852  	accounts := newAccounts(3)
   853  	genesis := &core.Genesis{
   854  		Config: params.TestChainConfig,
   855  		Alloc: core.GenesisAlloc{
   856  			accounts[0].addr: {Balance: big.NewInt(params.Ether)},
   857  			accounts[1].addr: {Balance: big.NewInt(params.Ether)},
   858  			accounts[2].addr: {Balance: big.NewInt(params.Ether)},
   859  		},
   860  	}
   861  	genBlocks := 50
   862  	signer := types.ShanghaiSigner{ChainId: big.NewInt(1)}
   863  
   864  	var (
   865  		ref   atomic.Uint32 // total refs has made
   866  		rel   atomic.Uint32 // total rels has made
   867  		nonce uint64
   868  	)
   869  	backend := newTestBackend(t, genBlocks, genesis, func(i int, b *core.BlockGen) {
   870  		// Transfer from account[0] to account[1]
   871  		//    value: 1000 wei
   872  		//    fee:   0 wei
   873  		for j := 0; j < i+1; j++ {
   874  			tx := types.NewTx(&types.DynamicFeeTx{
   875  				Nonce:     nonce,
   876  				To:        &accounts[1].addr,
   877  				Value:     big.NewInt(1000),
   878  				Gas:       params.TxGas,
   879  				GasFeeCap: b.BaseFee(),
   880  				Data:      nil,
   881  			})
   882  			signedTx, _ := types.SignTx(tx, signer, accounts[0].key)
   883  			b.AddTx(signedTx)
   884  			nonce += 1
   885  		}
   886  	})
   887  	backend.refHook = func() { ref.Add(1) }
   888  	backend.relHook = func() { rel.Add(1) }
   889  	api := NewAPI(backend)
   890  
   891  	single := `{"txHash":"0x0000000000000000000000000000000000000000000000000000000000000000","result":{"gas":21000,"failed":false,"returnValue":"","structLogs":[]}}`
   892  	var cases = []struct {
   893  		start  uint64
   894  		end    uint64
   895  		config *TraceConfig
   896  	}{
   897  		{0, 50, nil},  // the entire chain range, blocks [1, 50]
   898  		{10, 20, nil}, // the middle chain range, blocks [11, 20]
   899  	}
   900  	for _, c := range cases {
   901  		ref.Store(0)
   902  		rel.Store(0)
   903  
   904  		from, _ := api.blockByNumber(context.Background(), rpc.BlockNumber(c.start))
   905  		to, _ := api.blockByNumber(context.Background(), rpc.BlockNumber(c.end))
   906  		resCh := api.traceChain(from, to, c.config, nil)
   907  
   908  		next := c.start + 1
   909  		for result := range resCh {
   910  			if have, want := uint64(result.Block), next; have != want {
   911  				t.Fatalf("unexpected tracing block, have %d want %d", have, want)
   912  			}
   913  			if have, want := len(result.Traces), int(next); have != want {
   914  				t.Fatalf("unexpected result length, have %d want %d", have, want)
   915  			}
   916  			for _, trace := range result.Traces {
   917  				trace.TxHash = common.Hash{}
   918  				blob, _ := json.Marshal(trace)
   919  				if have, want := string(blob), single; have != want {
   920  					t.Fatalf("unexpected tracing result, have\n%v\nwant:\n%v", have, want)
   921  				}
   922  			}
   923  			next += 1
   924  		}
   925  		if next != c.end+1 {
   926  			t.Error("Missing tracing block")
   927  		}
   928  
   929  		if nref, nrel := ref.Load(), rel.Load(); nref != nrel {
   930  			t.Errorf("Ref and deref actions are not equal, ref %d rel %d", nref, nrel)
   931  		}
   932  	}
   933  }