github.com/core-coin/go-core/v2@v2.1.9/xcbclient/xcbclient_test.go (about)

     1  // Copyright 2016 by the Authors
     2  // This file is part of the go-core library.
     3  //
     4  // The go-core 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-core 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-core library. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  package xcbclient
    18  
    19  import (
    20  	"context"
    21  	"errors"
    22  	"fmt"
    23  	"math/big"
    24  	"reflect"
    25  	"testing"
    26  	"time"
    27  
    28  	c "github.com/core-coin/go-core/v2"
    29  	"github.com/core-coin/go-core/v2/common"
    30  	"github.com/core-coin/go-core/v2/consensus/cryptore"
    31  	"github.com/core-coin/go-core/v2/core"
    32  	"github.com/core-coin/go-core/v2/core/rawdb"
    33  	"github.com/core-coin/go-core/v2/core/types"
    34  	"github.com/core-coin/go-core/v2/crypto"
    35  	"github.com/core-coin/go-core/v2/node"
    36  	"github.com/core-coin/go-core/v2/params"
    37  	"github.com/core-coin/go-core/v2/xcb"
    38  )
    39  
    40  // Verify that Client implements the core interfaces.
    41  var (
    42  	_ = c.ChainReader(&Client{})
    43  	_ = c.TransactionReader(&Client{})
    44  	_ = c.ChainStateReader(&Client{})
    45  	_ = c.ChainSyncReader(&Client{})
    46  	_ = c.ContractCaller(&Client{})
    47  	_ = c.EnergyEstimator(&Client{})
    48  	_ = c.EnergyPricer(&Client{})
    49  	_ = c.LogFilterer(&Client{})
    50  	_ = c.PendingStateReader(&Client{})
    51  	// _ = c.PendingStateEventer(&Client{})
    52  	_ = c.PendingContractCaller(&Client{})
    53  )
    54  
    55  func TestToFilterArg(t *testing.T) {
    56  	blockHashErr := fmt.Errorf("cannot specify both BlockHash and FromBlock/ToBlock")
    57  	addr, err := common.HexToAddress("cb44d36722adec3edcb29c8e7b5a47f352d701393462")
    58  	if err != nil {
    59  		t.Error(err)
    60  	}
    61  	addresses := []common.Address{
    62  		addr,
    63  	}
    64  	blockHash := common.HexToHash(
    65  		"0xeb94bb7d78b73657a9d7a99792413f50c0a45c51fc62bdcb08a53f18e9a2b4eb",
    66  	)
    67  
    68  	for _, testCase := range []struct {
    69  		name   string
    70  		input  c.FilterQuery
    71  		output interface{}
    72  		err    error
    73  	}{
    74  		{
    75  			"without BlockHash",
    76  			c.FilterQuery{
    77  				Addresses: addresses,
    78  				FromBlock: big.NewInt(1),
    79  				ToBlock:   big.NewInt(2),
    80  				Topics:    [][]common.Hash{},
    81  			},
    82  			map[string]interface{}{
    83  				"address":   addresses,
    84  				"fromBlock": "0x1",
    85  				"toBlock":   "0x2",
    86  				"topics":    [][]common.Hash{},
    87  			},
    88  			nil,
    89  		},
    90  		{
    91  			"with nil fromBlock and nil toBlock",
    92  			c.FilterQuery{
    93  				Addresses: addresses,
    94  				Topics:    [][]common.Hash{},
    95  			},
    96  			map[string]interface{}{
    97  				"address":   addresses,
    98  				"fromBlock": "0x0",
    99  				"toBlock":   "latest",
   100  				"topics":    [][]common.Hash{},
   101  			},
   102  			nil,
   103  		},
   104  		{
   105  			"with negative fromBlock and negative toBlock",
   106  			c.FilterQuery{
   107  				Addresses: addresses,
   108  				FromBlock: big.NewInt(-1),
   109  				ToBlock:   big.NewInt(-1),
   110  				Topics:    [][]common.Hash{},
   111  			},
   112  			map[string]interface{}{
   113  				"address":   addresses,
   114  				"fromBlock": "pending",
   115  				"toBlock":   "pending",
   116  				"topics":    [][]common.Hash{},
   117  			},
   118  			nil,
   119  		},
   120  		{
   121  			"with blockhash",
   122  			c.FilterQuery{
   123  				Addresses: addresses,
   124  				BlockHash: &blockHash,
   125  				Topics:    [][]common.Hash{},
   126  			},
   127  			map[string]interface{}{
   128  				"address":   addresses,
   129  				"blockHash": blockHash,
   130  				"topics":    [][]common.Hash{},
   131  			},
   132  			nil,
   133  		},
   134  		{
   135  			"with blockhash and from block",
   136  			c.FilterQuery{
   137  				Addresses: addresses,
   138  				BlockHash: &blockHash,
   139  				FromBlock: big.NewInt(1),
   140  				Topics:    [][]common.Hash{},
   141  			},
   142  			nil,
   143  			blockHashErr,
   144  		},
   145  		{
   146  			"with blockhash and to block",
   147  			c.FilterQuery{
   148  				Addresses: addresses,
   149  				BlockHash: &blockHash,
   150  				ToBlock:   big.NewInt(1),
   151  				Topics:    [][]common.Hash{},
   152  			},
   153  			nil,
   154  			blockHashErr,
   155  		},
   156  		{
   157  			"with blockhash and both from / to block",
   158  			c.FilterQuery{
   159  				Addresses: addresses,
   160  				BlockHash: &blockHash,
   161  				FromBlock: big.NewInt(1),
   162  				ToBlock:   big.NewInt(2),
   163  				Topics:    [][]common.Hash{},
   164  			},
   165  			nil,
   166  			blockHashErr,
   167  		},
   168  	} {
   169  		t.Run(testCase.name, func(t *testing.T) {
   170  			output, err := toFilterArg(testCase.input)
   171  			if (testCase.err == nil) != (err == nil) {
   172  				t.Fatalf("expected error %v but got %v", testCase.err, err)
   173  			}
   174  			if testCase.err != nil {
   175  				if testCase.err.Error() != err.Error() {
   176  					t.Fatalf("expected error %v but got %v", testCase.err, err)
   177  				}
   178  			} else if !reflect.DeepEqual(testCase.output, output) {
   179  				t.Fatalf("expected filter arg %v but got %v", testCase.output, output)
   180  			}
   181  		})
   182  	}
   183  }
   184  
   185  var (
   186  	testKey, _  = crypto.UnmarshalPrivateKeyHex("89bdfaa2b6f9c30b94ee98fec96c58ff8507fabf49d36a6267e6cb5516eaa2a9e854eccc041f9f67e109d0eb4f653586855355c5b2b87bb313")
   187  	testBalance = big.NewInt(2e10)
   188  )
   189  
   190  func newTestBackend(t *testing.T) (*node.Node, []*types.Block) {
   191  	// Generate test chain.
   192  	genesis, blocks := generateTestChain()
   193  	// Create node
   194  	n, err := node.New(&node.Config{})
   195  	if err != nil {
   196  		t.Fatalf("can't create new node: %v", err)
   197  	}
   198  	// Create Core Service
   199  	config := &xcb.Config{NetworkId: genesis.Config.NetworkID.Uint64(), Genesis: genesis}
   200  	config.Cryptore.PowMode = cryptore.ModeFake
   201  	xcbservice, err := xcb.New(n, config)
   202  	if err != nil {
   203  		t.Fatalf("can't create new core service: %v", err)
   204  	}
   205  	// Import the test chain.
   206  	if err := n.Start(); err != nil {
   207  		t.Fatalf("can't start test node: %v", err)
   208  	}
   209  	if _, err := xcbservice.BlockChain().InsertChain(blocks[1:]); err != nil {
   210  		t.Fatalf("can't import test blocks: %v", err)
   211  	}
   212  	return n, blocks
   213  }
   214  
   215  func generateTestChain() (*core.Genesis, []*types.Block) {
   216  	db := rawdb.NewMemoryDatabase()
   217  	config := params.MainnetChainConfig
   218  	genesis := &core.Genesis{
   219  		Coinbase:  core.DefaultCoinbaseMainnet,
   220  		Config:    config,
   221  		Alloc:     core.GenesisAlloc{testKey.Address(): {Balance: testBalance}},
   222  		ExtraData: []byte("test genesis"),
   223  		Timestamp: 9000,
   224  	}
   225  	generate := func(i int, g *core.BlockGen) {
   226  		g.OffsetTime(5)
   227  		g.SetExtra([]byte("test"))
   228  	}
   229  	gblock := genesis.ToBlock(db)
   230  	engine := cryptore.NewFaker()
   231  	blocks, _ := core.GenerateChain(config, gblock, engine, db, 1, generate)
   232  	blocks = append([]*types.Block{gblock}, blocks...)
   233  	return genesis, blocks
   234  }
   235  
   236  func TestHeader(t *testing.T) {
   237  	backend, chain := newTestBackend(t)
   238  	client, err := backend.Attach()
   239  	if err != nil {
   240  		t.Error(err)
   241  	}
   242  	defer backend.Close()
   243  	defer client.Close()
   244  
   245  	tests := map[string]struct {
   246  		block   *big.Int
   247  		want    *types.Header
   248  		wantErr error
   249  	}{
   250  		"genesis": {
   251  			block: big.NewInt(0),
   252  			want:  chain[0].Header(),
   253  		},
   254  		"first_block": {
   255  			block: big.NewInt(1),
   256  			want:  chain[1].Header(),
   257  		},
   258  		"future_block": {
   259  			block: big.NewInt(1000000000),
   260  			want:  nil,
   261  		},
   262  	}
   263  	for name, tt := range tests {
   264  		t.Run(name, func(t *testing.T) {
   265  			ec := NewClient(client)
   266  			ctx, cancel := context.WithTimeout(context.Background(), 200*time.Millisecond)
   267  			defer cancel()
   268  
   269  			got, err := ec.HeaderByNumber(ctx, tt.block)
   270  			if tt.wantErr != nil && (err == nil || err.Error() != tt.wantErr.Error()) {
   271  				t.Fatalf("HeaderByNumber(%v) error = %q, want %q", tt.block, err, tt.wantErr)
   272  			}
   273  			if got != nil && got.Number.Sign() == 0 {
   274  				got.Number = big.NewInt(0) // hack to make DeepEqual work
   275  			}
   276  			if !reflect.DeepEqual(got, tt.want) {
   277  				t.Fatalf("HeaderByNumber(%v)\n   = %v\nwant %v", tt.block, got, tt.want)
   278  			}
   279  		})
   280  	}
   281  }
   282  
   283  func TestBalanceAt(t *testing.T) {
   284  	backend, _ := newTestBackend(t)
   285  	client, _ := backend.Attach()
   286  	defer backend.Close()
   287  	defer client.Close()
   288  
   289  	tests := map[string]struct {
   290  		account common.Address
   291  		block   *big.Int
   292  		want    *big.Int
   293  		wantErr error
   294  	}{
   295  		"valid_account": {
   296  			account: testKey.Address(),
   297  			block:   big.NewInt(1),
   298  			want:    testBalance,
   299  		},
   300  		"non_existent_account": {
   301  			account: common.Address{1},
   302  			block:   big.NewInt(1),
   303  			want:    big.NewInt(0),
   304  		},
   305  		"future_block": {
   306  			account: testKey.Address(),
   307  			block:   big.NewInt(1000000000),
   308  			want:    big.NewInt(0),
   309  			wantErr: errors.New("header not found"),
   310  		},
   311  	}
   312  	for name, tt := range tests {
   313  		t.Run(name, func(t *testing.T) {
   314  			ec := NewClient(client)
   315  			ctx, cancel := context.WithTimeout(context.Background(), 100*time.Millisecond)
   316  			defer cancel()
   317  
   318  			got, err := ec.BalanceAt(ctx, tt.account, tt.block)
   319  			if tt.wantErr != nil && (err == nil || err.Error() != tt.wantErr.Error()) {
   320  				t.Fatalf("BalanceAt(%x, %v) error = %q, want %q", tt.account, tt.block, err, tt.wantErr)
   321  			}
   322  			if got.Cmp(tt.want) != 0 {
   323  				t.Fatalf("BalanceAt(%x, %v) = %v, want %v", tt.account, tt.block, got, tt.want)
   324  			}
   325  		})
   326  	}
   327  }
   328  
   329  func TestTransactionInBlockInterrupted(t *testing.T) {
   330  	backend, _ := newTestBackend(t)
   331  	client, _ := backend.Attach()
   332  	defer backend.Close()
   333  	defer client.Close()
   334  
   335  	ec := NewClient(client)
   336  	ctx, cancel := context.WithCancel(context.Background())
   337  	cancel()
   338  	tx, err := ec.TransactionInBlock(ctx, common.Hash{1}, 1)
   339  	if tx != nil {
   340  		t.Fatal("transaction should be nil")
   341  	}
   342  	if err == nil {
   343  		t.Fatal("error should not be nil")
   344  	}
   345  }
   346  
   347  func TestNetworkID(t *testing.T) {
   348  	backend, _ := newTestBackend(t)
   349  	client, _ := backend.Attach()
   350  	defer backend.Close()
   351  	defer client.Close()
   352  	ec := NewClient(client)
   353  
   354  	id, err := ec.NetworkID(context.Background())
   355  	if err != nil {
   356  		t.Fatalf("unexpected error: %v", err)
   357  	}
   358  	if id == nil || id.Cmp(params.MainnetChainConfig.NetworkID) != 0 {
   359  		t.Fatalf("NetworkID returned wrong number: %+v", id)
   360  	}
   361  }
   362  
   363  func TestBlockNumber(t *testing.T) {
   364  	backend, _ := newTestBackend(t)
   365  	client, _ := backend.Attach()
   366  	defer backend.Close()
   367  	defer client.Close()
   368  	ec := NewClient(client)
   369  
   370  	blockNumber, err := ec.BlockNumber(context.Background())
   371  	if err != nil {
   372  		t.Fatalf("unexpected error: %v", err)
   373  	}
   374  	if blockNumber != 1 {
   375  		t.Fatalf("BlockNumber returned wrong number: %d", blockNumber)
   376  	}
   377  }