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

     1  // Copyright 2020 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 core
    18  
    19  import (
    20  	"math/big"
    21  	"testing"
    22  
    23  	"golang.org/x/crypto/sha3"
    24  
    25  	"github.com/core-coin/go-core/v2/consensus/cryptore"
    26  
    27  	"github.com/core-coin/go-core/v2/common"
    28  	"github.com/core-coin/go-core/v2/consensus"
    29  	"github.com/core-coin/go-core/v2/core/rawdb"
    30  	"github.com/core-coin/go-core/v2/core/types"
    31  	"github.com/core-coin/go-core/v2/core/vm"
    32  	"github.com/core-coin/go-core/v2/crypto"
    33  	"github.com/core-coin/go-core/v2/params"
    34  	"github.com/core-coin/go-core/v2/trie"
    35  )
    36  
    37  // TestStateProcessorErrors tests the output from the 'core' errors
    38  // as defined in core/error.go. These errors are generated when the
    39  // blockchain imports bad blocks, meaning blocks which have valid headers but
    40  // contain invalid transactions
    41  func TestStateProcessorErrors(t *testing.T) {
    42  	var (
    43  		signer     = types.NewNucleusSigner(big.NewInt(1))
    44  		testKey, _ = crypto.UnmarshalPrivateKeyHex("89bdfaa2b6f9c30b94ee98fec96c58ff8507fabf49d36a6267e6cb5516eaa2a9e854eccc041f9f67e109d0eb4f653586855355c5b2b87bb313")
    45  		db         = rawdb.NewMemoryDatabase()
    46  		gspec      = &Genesis{
    47  			Config: params.MainnetChainConfig,
    48  		}
    49  		genesis         = gspec.MustCommit(db)
    50  		blockchain, err = NewBlockChain(db, nil, gspec.Config, cryptore.NewFaker(), vm.Config{}, nil, nil)
    51  	)
    52  	if err != nil {
    53  		t.Error(err)
    54  	}
    55  	defer blockchain.Stop()
    56  	var makeTx = func(nonce uint64, to common.Address, amount *big.Int, energyLimit uint64, energyPrice *big.Int, data []byte) *types.Transaction {
    57  		tx, err := types.SignTx(types.NewTransaction(nonce, to, amount, energyLimit, energyPrice, data), signer, testKey)
    58  		if err != nil {
    59  			t.Error(err)
    60  		}
    61  		return tx
    62  	}
    63  	for i, tt := range []struct {
    64  		txs  []*types.Transaction
    65  		want string
    66  	}{
    67  		{
    68  			txs: []*types.Transaction{
    69  				makeTx(0, common.Address{}, big.NewInt(0), params.TxEnergy, nil, nil),
    70  				makeTx(0, common.Address{}, big.NewInt(0), params.TxEnergy, nil, nil),
    71  			},
    72  			want: "could not apply tx 1 [0xf8bc550eaed9cdbdee2897934410fbff78ba05f3cfa3d1cbc53ade58d6f91eea]: nonce too low: address cb53c378bf81ade6f8e505ac7c298c84f7709f9b5a4e, tx: 0 state: 1",
    73  		},
    74  		{
    75  			txs: []*types.Transaction{
    76  				makeTx(100, common.Address{}, big.NewInt(0), params.TxEnergy, nil, nil),
    77  			},
    78  			want: "could not apply tx 0 [0xb0390f103112930b5f3105c7b4cf6f36ed5586d77654e28b97fa848c0dd1fde3]: nonce too high: address cb53c378bf81ade6f8e505ac7c298c84f7709f9b5a4e, tx: 100 state: 0",
    79  		},
    80  		{
    81  			txs: []*types.Transaction{
    82  				makeTx(0, common.Address{}, big.NewInt(0), 21000000, nil, nil),
    83  			},
    84  			want: "could not apply tx 0 [0x5b7c1c6a4531a327422151ab1fc7e62e67ae13456357bdf2ed14a6388bf4c23a]: energy limit reached",
    85  		},
    86  		{
    87  			txs: []*types.Transaction{
    88  				makeTx(0, common.Address{}, big.NewInt(1), params.TxEnergy, nil, nil),
    89  			},
    90  			want: "could not apply tx 0 [0x9eca1a545fea71373e72f0cfc881047b6c4b191160ba9e7a50fdf6775c228557]: insufficient funds for transfer: address cb53c378bf81ade6f8e505ac7c298c84f7709f9b5a4e",
    91  		},
    92  		{
    93  			txs: []*types.Transaction{
    94  				makeTx(0, common.Address{}, big.NewInt(0), params.TxEnergy, big.NewInt(0xffffff), nil),
    95  			},
    96  			want: "could not apply tx 0 [0x67c36b9e6c20ee836cbf7cd0f91ef407902cb33b2cb0529cb6ae5bf7c54fb7a4]: insufficient funds for energy * price + value: address cb53c378bf81ade6f8e505ac7c298c84f7709f9b5a4e have 0 want 352321515000",
    97  		},
    98  		{
    99  			txs: []*types.Transaction{
   100  				makeTx(0, common.Address{}, big.NewInt(0), params.TxEnergy, nil, nil),
   101  				makeTx(1, common.Address{}, big.NewInt(0), params.TxEnergy, nil, nil),
   102  				makeTx(2, common.Address{}, big.NewInt(0), params.TxEnergy, nil, nil),
   103  				makeTx(3, common.Address{}, big.NewInt(0), params.TxEnergy-1000, big.NewInt(0), nil),
   104  			},
   105  			want: "could not apply tx 3 [0x3590cc281751dce7f99b3cc2a32f74367353236004c9b0491aa05a37500e52fe]: intrinsic energy too low: have 20000, want 21000",
   106  		},
   107  		// The last 'core' error is ErrEnergyUintOverflow: "energy uint64 overflow", but in order to
   108  		// trigger that one, we'd have to allocate a _huge_ chunk of data, such that the
   109  		// multiplication len(data) +energy_per_byte overflows uint64. Not testable at the moment
   110  	} {
   111  		block := GenerateBadBlock(genesis, cryptore.NewFaker(), tt.txs)
   112  		_, err := blockchain.InsertChain(types.Blocks{block})
   113  		if err == nil {
   114  			t.Fatal("block imported without errors")
   115  		}
   116  		if have, want := err.Error(), tt.want; have != want {
   117  			t.Errorf("test %d:\nhave \"%v\"\nwant \"%v\"\n", i, have, want)
   118  		}
   119  	}
   120  }
   121  
   122  // GenerateBadBlock constructs a "block" which contains the transactions. The transactions are not expected to be
   123  // valid, and no proper post-state can be made. But from the perspective of the blockchain, the block is sufficiently
   124  // valid to be considered for import:
   125  // - valid pow (fake), ancestry, difficulty, energylimit etc
   126  func GenerateBadBlock(parent *types.Block, engine consensus.Engine, txs types.Transactions) *types.Block {
   127  	header := &types.Header{
   128  		ParentHash: parent.Hash(),
   129  		Coinbase:   parent.Coinbase(),
   130  		Difficulty: engine.CalcDifficulty(&fakeChainReader{params.MainnetChainConfig}, parent.Time()+10, &types.Header{
   131  			Number:     parent.Number(),
   132  			Time:       parent.Time(),
   133  			Difficulty: parent.Difficulty(),
   134  			UncleHash:  parent.UncleHash(),
   135  		}),
   136  		EnergyLimit: CalcEnergyLimit(parent, parent.EnergyLimit(), parent.EnergyLimit()),
   137  		Number:      new(big.Int).Add(parent.Number(), common.Big1),
   138  		Time:        parent.Time() + 10,
   139  		UncleHash:   types.EmptyUncleHash,
   140  	}
   141  	var receipts []*types.Receipt
   142  
   143  	// The post-state result doesn't need to be correct (this is a bad block), but we do need something there
   144  	// Preferably something unique. So let's use a combo of blocknum + txhash
   145  	hasher := sha3.New256()
   146  	hasher.Write(header.Number.Bytes())
   147  	var cumulativeEnergy uint64
   148  	for _, tx := range txs {
   149  		txh := tx.Hash()
   150  		hasher.Write(txh[:])
   151  		receipt := types.NewReceipt(nil, false, cumulativeEnergy+tx.Energy())
   152  		receipt.TxHash = tx.Hash()
   153  		receipt.EnergyUsed = tx.Energy()
   154  		receipts = append(receipts, receipt)
   155  		cumulativeEnergy += tx.Energy()
   156  	}
   157  	header.Root = common.BytesToHash(hasher.Sum(nil))
   158  	// Assemble and return the final block for sealing
   159  	return types.NewBlock(header, txs, nil, receipts, new(trie.Trie))
   160  }