github.com/codingfuture/orig-energi3@v0.8.4/energi/consensus/pos_test.go (about)

     1  // Copyright 2019 The Energi Core Authors
     2  // This file is part of the Energi Core library.
     3  //
     4  // The Energi 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 Energi 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 Energi Core library. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  package consensus
    18  
    19  import (
    20  	"crypto/ecdsa"
    21  	"crypto/rand"
    22  	"math/big"
    23  	"testing"
    24  
    25  	"github.com/ethereum/go-ethereum/common"
    26  	eth_consensus "github.com/ethereum/go-ethereum/consensus"
    27  	"github.com/ethereum/go-ethereum/core"
    28  	"github.com/ethereum/go-ethereum/core/types"
    29  	"github.com/ethereum/go-ethereum/core/vm"
    30  	"github.com/ethereum/go-ethereum/crypto"
    31  	"github.com/ethereum/go-ethereum/ethdb"
    32  	"github.com/ethereum/go-ethereum/log"
    33  	"github.com/ethereum/go-ethereum/params"
    34  
    35  	"github.com/stretchr/testify/assert"
    36  
    37  	energi_params "energi.world/core/gen3/energi/params"
    38  )
    39  
    40  func TestPoSChain(t *testing.T) {
    41  	t.Parallel()
    42  	log.Root().SetHandler(log.StdoutHandler)
    43  
    44  	results := make(chan *eth_consensus.SealResult, 1)
    45  	stop := make(chan struct{})
    46  
    47  	signers := make(map[common.Address]*ecdsa.PrivateKey, 61)
    48  	addresses := make([]common.Address, 0, 60)
    49  	alloc := make(core.GenesisAlloc, 61)
    50  	for i := 0; i < 60; i++ {
    51  		k, _ := ecdsa.GenerateKey(crypto.S256(), rand.Reader)
    52  		a := crypto.PubkeyToAddress(k.PublicKey)
    53  
    54  		signers[a] = k
    55  		addresses = append(addresses, a)
    56  		alloc[a] = core.GenesisAccount{
    57  			Balance: minStake,
    58  		}
    59  	}
    60  	alloc[energi_params.Energi_MigrationContract] = core.GenesisAccount{
    61  		Balance: minStake,
    62  	}
    63  	migrationSigner := addresses[59]
    64  	signers[energi_params.Energi_MigrationContract] = signers[migrationSigner]
    65  
    66  	testdb := ethdb.NewMemDatabase()
    67  	engine := New(&params.EnergiConfig{MigrationSigner: migrationSigner}, testdb)
    68  	var header *types.Header
    69  
    70  	engine.testing = true
    71  	engine.SetMinerCB(
    72  		func() []common.Address {
    73  			if header.Number.Uint64() == 1 {
    74  				return []common.Address{
    75  					energi_params.Energi_MigrationContract,
    76  				}
    77  			}
    78  
    79  			return addresses
    80  		},
    81  		func(addr common.Address, hash []byte) ([]byte, error) {
    82  			return crypto.Sign(hash, signers[addr])
    83  		},
    84  		func() int { return 1 },
    85  	)
    86  
    87  	chainConfig := *params.EnergiTestnetChainConfig
    88  	chainConfig.Energi = &params.EnergiConfig{
    89  		MigrationSigner: migrationSigner,
    90  	}
    91  
    92  	var (
    93  		gspec = &core.Genesis{
    94  			Config:     &chainConfig,
    95  			GasLimit:   8000000,
    96  			Timestamp:  1000,
    97  			Difficulty: big.NewInt(1),
    98  			Coinbase:   energi_params.Energi_Treasury,
    99  			Alloc:      alloc,
   100  			Xfers:      core.DeployEnergiGovernance(&chainConfig),
   101  		}
   102  		genesis = gspec.MustCommit(testdb)
   103  
   104  		now = engine.now()
   105  	)
   106  
   107  	chain, err := core.NewBlockChain(testdb, nil, &chainConfig, engine, vm.Config{}, nil)
   108  	assert.Empty(t, err)
   109  	defer chain.Stop()
   110  
   111  	//--
   112  	_, err = chain.InsertChain([]*types.Block{genesis})
   113  	assert.Empty(t, err)
   114  
   115  	parent := chain.GetHeaderByHash(genesis.Hash())
   116  	assert.NotEmpty(t, parent)
   117  
   118  	iterCount := 150
   119  	//iterMid := iterCount * 2 / 3
   120  
   121  	engine.diffFn = func(ChainReader, uint64, *types.Header, *timeTarget) *big.Int {
   122  		return common.Big1
   123  	}
   124  
   125  	for i := 1; i < iterCount; i++ {
   126  		number := new(big.Int).Add(parent.Number, common.Big1)
   127  
   128  		//---
   129  		header = &types.Header{
   130  			ParentHash: parent.Hash(),
   131  			Coinbase:   common.Address{},
   132  			GasLimit:   parent.GasLimit,
   133  			Number:     number,
   134  			Time:       parent.Time,
   135  		}
   136  		blstate := chain.CalculateBlockState(header.ParentHash, parent.Number.Uint64())
   137  		assert.NotEmpty(t, blstate)
   138  
   139  		err = engine.Prepare(chain, header)
   140  		assert.Empty(t, err)
   141  		assert.NotEmpty(t, header.Difficulty)
   142  		txs := types.Transactions{}
   143  		receipts := []*types.Receipt{}
   144  		if i == 1 {
   145  			tx := migrationTx(
   146  				types.NewEIP155Signer(chainConfig.ChainID), header,
   147  				&snapshot{
   148  					Txouts: []snapshotItem{
   149  						{
   150  							Owner:  "t6vtJKxdjaJdofaUrx7w4xUs5bMcjDq5R2",
   151  							Amount: big.NewInt(10228000000),
   152  							Atype:  "pubkeyhash",
   153  						},
   154  					},
   155  				}, engine)
   156  			receipt, _, err := core.ApplyTransaction(
   157  				&chainConfig, chain, &header.Coinbase,
   158  				new(core.GasPool).AddGas(header.GasLimit),
   159  				blstate, header, tx,
   160  				&header.GasUsed, *chain.GetVMConfig())
   161  			assert.Empty(t, err)
   162  			txs = append(txs, tx)
   163  			receipts = append(receipts, receipt)
   164  		}
   165  		block, receipts, err := engine.Finalize(
   166  			chain, header, blstate, txs, nil, receipts)
   167  		assert.Empty(t, err)
   168  
   169  		if i == 1 {
   170  			assert.Equal(t, 1, len(receipts))
   171  		} else {
   172  			assert.Empty(t, receipts)
   173  		}
   174  
   175  		//---
   176  		err = engine.Seal(chain, block, results, stop)
   177  		assert.Empty(t, err)
   178  
   179  		seal_res := <-results
   180  		block = seal_res.Block
   181  		blstate = seal_res.NewState
   182  		receipts = seal_res.Receipts
   183  		assert.NotEmpty(t, block)
   184  		assert.NotEmpty(t, blstate)
   185  		assert.NotEmpty(t, receipts)
   186  		header = block.Header()
   187  		//assert.NotEqual(t, parent.Coinbase, header.Coinbase, "Header %v", i)
   188  		assert.NotEqual(t, parent.Coinbase, common.Address{}, "Header %v", i)
   189  		err = engine.VerifySeal(chain, header)
   190  		assert.Empty(t, err)
   191  
   192  		// Test consensus tx check during block processing
   193  		//---
   194  		if i == 2 {
   195  			tmptxs := block.Transactions()
   196  			tmpheader := *header
   197  
   198  			assert.Equal(t, len(tmptxs), 1)
   199  
   200  			_, _, err = engine.Finalize(
   201  				chain, &tmpheader, blstate.Copy(), tmptxs, nil, receipts)
   202  			assert.Empty(t, err)
   203  
   204  			_, _, err = engine.Finalize(
   205  				chain, &tmpheader, blstate.Copy(), append(tmptxs, tmptxs[len(tmptxs)-1]), nil, receipts)
   206  			assert.Equal(t, eth_consensus.ErrInvalidConsensusTx, err)
   207  
   208  			_, _, err = engine.Finalize(
   209  				chain, &tmpheader, blstate.Copy(),
   210  				append(tmptxs[:len(tmptxs)-1], tmptxs[len(tmptxs)-1].WithConsensusSender(common.Address{})),
   211  				nil, receipts)
   212  			assert.Equal(t, eth_consensus.ErrInvalidConsensusTx, err)
   213  		}
   214  
   215  		// Time tests
   216  		//---
   217  		tt := engine.calcTimeTarget(chain, parent)
   218  		assert.True(t, tt.max_time >= now)
   219  		assert.True(t, tt.max_time <= engine.now()+30)
   220  
   221  		if i < 60 {
   222  			assert.Equal(t, header.Time, parent.Time+30)
   223  
   224  			assert.Equal(t, tt.min_time, header.Time)
   225  			assert.Equal(t, tt.block_target, header.Time+30)
   226  		} else if i < 61 {
   227  			assert.Equal(t, header.Time, genesis.Time()+3570)
   228  			assert.Equal(t, header.Time, parent.Time+1800)
   229  
   230  			assert.Equal(t, tt.min_time, header.Time)
   231  			assert.Equal(t, tt.block_target, parent.Time+60)
   232  		} else if i < 62 {
   233  			assert.Equal(t, header.Time, genesis.Time()+3600)
   234  		}
   235  
   236  		assert.True(t, parent.Time < tt.min_time, "Header %v", i)
   237  
   238  		_, err = chain.WriteBlockWithState(block, receipts, blstate)
   239  		assert.Empty(t, err)
   240  
   241  		// Stake amount tests
   242  		//---
   243  		// TODO:
   244  
   245  		//---
   246  
   247  		parent = header
   248  	}
   249  }
   250  
   251  func TestPoSDiffV1(t *testing.T) {
   252  	t.Parallel()
   253  	log.Root().SetHandler(log.StdoutHandler)
   254  
   255  	type TC struct {
   256  		parent  int64
   257  		time    uint64
   258  		min     uint64
   259  		btarget uint64
   260  		ptarget uint64
   261  		result  uint64
   262  	}
   263  
   264  	tests := []TC{
   265  		{
   266  			parent:  100,
   267  			time:    61,
   268  			min:     31,
   269  			btarget: 61,
   270  			ptarget: 61,
   271  			result:  100,
   272  		},
   273  		{
   274  			parent:  100,
   275  			time:    31,
   276  			min:     31,
   277  			btarget: 61,
   278  			ptarget: 61,
   279  			result:  1744,
   280  		},
   281  		{
   282  			parent:  100,
   283  			time:    31,
   284  			min:     31,
   285  			btarget: 51,
   286  			ptarget: 71,
   287  			result:  1744,
   288  		},
   289  		{
   290  			parent:  100,
   291  			time:    31,
   292  			min:     61,
   293  			btarget: 31,
   294  			ptarget: 31,
   295  			result:  1744,
   296  		},
   297  		{
   298  			parent:  100,
   299  			time:    31,
   300  			min:     31,
   301  			btarget: 31,
   302  			ptarget: 31,
   303  			result:  100,
   304  		},
   305  		{
   306  			parent:  1744,
   307  			time:    91,
   308  			min:     31,
   309  			btarget: 61,
   310  			ptarget: 61,
   311  			result:  403,
   312  		},
   313  		{
   314  			parent:  1744,
   315  			time:    121,
   316  			min:     31,
   317  			btarget: 61,
   318  			ptarget: 61,
   319  			result:  93,
   320  		},
   321  		{
   322  			parent:  1744,
   323  			time:    200,
   324  			min:     31,
   325  			btarget: 61,
   326  			ptarget: 61,
   327  			result:  4,
   328  		},
   329  		{
   330  			parent:  1744,
   331  			time:    181,
   332  			min:     31,
   333  			btarget: 61,
   334  			ptarget: 61,
   335  			result:  4,
   336  		},
   337  	}
   338  
   339  	for i, tc := range tests {
   340  		parent := &types.Header{
   341  			Difficulty: big.NewInt(tc.parent),
   342  		}
   343  		tt := &timeTarget{
   344  			min_time:      tc.min,
   345  			block_target:  tc.btarget,
   346  			period_target: tc.ptarget,
   347  		}
   348  
   349  		res := calcPoSDifficultyV1(nil, tc.time, parent, tt)
   350  		assert.Equal(t, tc.result, res.Uint64(), "TC %v", i)
   351  	}
   352  }