mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-06-19 21:31:37 +00:00
Fix XDC forking incident with tests
This commit is contained in:
parent
abc0f98eed
commit
7b7e34ae00
8 changed files with 579 additions and 29 deletions
|
|
@ -28,6 +28,7 @@ import (
|
|||
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/common/math"
|
||||
"github.com/ethereum/go-ethereum/consensus/XDPoS"
|
||||
"github.com/ethereum/go-ethereum/consensus/ethash"
|
||||
"github.com/ethereum/go-ethereum/core"
|
||||
"github.com/ethereum/go-ethereum/core/bloombits"
|
||||
|
|
@ -63,6 +64,28 @@ type SimulatedBackend struct {
|
|||
config *params.ChainConfig
|
||||
}
|
||||
|
||||
// XDC simulated backend for testing purpose.
|
||||
func NewXDCSimulatedBackend(alloc core.GenesisAlloc) *SimulatedBackend {
|
||||
database := ethdb.NewMemDatabase()
|
||||
genesis := core.Genesis{
|
||||
GasLimit: 10000000, // need this big, support initial smart contract
|
||||
Config: params.TestXDPoSMockChainConfig,
|
||||
Alloc: alloc,
|
||||
ExtraData: append(make([]byte, 32), make([]byte, 65)...),
|
||||
}
|
||||
genesis.MustCommit(database)
|
||||
blockchain, _ := core.NewBlockChain(database, nil, genesis.Config, XDPoS.NewFaker(database), vm.Config{}, nil)
|
||||
|
||||
backend := &SimulatedBackend{
|
||||
database: database,
|
||||
blockchain: blockchain,
|
||||
config: genesis.Config,
|
||||
events: filters.NewEventSystem(new(event.TypeMux), &filterBackend{database, blockchain}, false),
|
||||
}
|
||||
backend.rollback()
|
||||
return backend
|
||||
}
|
||||
|
||||
// NewSimulatedBackend creates a new binding backend using a simulated blockchain
|
||||
// for testing purposes.
|
||||
func NewSimulatedBackend(alloc core.GenesisAlloc, gasLimit uint64) *SimulatedBackend {
|
||||
|
|
@ -102,7 +125,7 @@ func (b *SimulatedBackend) Rollback() {
|
|||
}
|
||||
|
||||
func (b *SimulatedBackend) rollback() {
|
||||
blocks, _ := core.GenerateChain(b.config, b.blockchain.CurrentBlock(), ethash.NewFaker(), b.database, 1, func(int, *core.BlockGen) {})
|
||||
blocks, _ := core.GenerateChain(b.config, b.blockchain.CurrentBlock(), XDPoS.GetFaker(), b.database, 1, func(int, *core.BlockGen) {})
|
||||
statedb, _ := b.blockchain.State()
|
||||
|
||||
b.pendingBlock = blocks[0]
|
||||
|
|
@ -319,7 +342,7 @@ func (b *SimulatedBackend) SendTransaction(ctx context.Context, tx *types.Transa
|
|||
panic(fmt.Errorf("invalid transaction nonce: got %d, want %d", tx.Nonce(), nonce))
|
||||
}
|
||||
|
||||
blocks, _ := core.GenerateChain(b.config, b.blockchain.CurrentBlock(), ethash.NewFaker(), b.database, 1, func(number int, block *core.BlockGen) {
|
||||
blocks, _ := core.GenerateChain(b.config, b.blockchain.CurrentBlock(), XDPoS.GetFaker(), b.database, 1, func(number int, block *core.BlockGen) {
|
||||
for _, tx := range b.pendingBlock.Transactions() {
|
||||
block.AddTxWithChain(b.blockchain, tx)
|
||||
}
|
||||
|
|
@ -404,7 +427,7 @@ func (b *SimulatedBackend) SubscribeFilterLogs(ctx context.Context, query ethere
|
|||
func (b *SimulatedBackend) AdjustTime(adjustment time.Duration) error {
|
||||
b.mu.Lock()
|
||||
defer b.mu.Unlock()
|
||||
blocks, _ := core.GenerateChain(b.config, b.blockchain.CurrentBlock(), ethash.NewFaker(), b.database, 1, func(number int, block *core.BlockGen) {
|
||||
blocks, _ := core.GenerateChain(b.config, b.blockchain.CurrentBlock(), XDPoS.GetFaker(), b.database, 1, func(number int, block *core.BlockGen) {
|
||||
for _, tx := range b.pendingBlock.Transactions() {
|
||||
block.AddTx(tx)
|
||||
}
|
||||
|
|
@ -418,6 +441,10 @@ func (b *SimulatedBackend) AdjustTime(adjustment time.Duration) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (b *SimulatedBackend) GetBlockChain() *core.BlockChain {
|
||||
return b.blockchain
|
||||
}
|
||||
|
||||
// callmsg implements core.Message to allow passing it as a transaction simulator.
|
||||
type callmsg struct {
|
||||
ethereum.CallMsg
|
||||
|
|
|
|||
|
|
@ -264,6 +264,37 @@ func New(config *params.XDPoSConfig, db ethdb.Database) *XDPoS {
|
|||
}
|
||||
}
|
||||
|
||||
var engine *XDPoS
|
||||
|
||||
// NewFullFaker creates an ethash consensus engine with a full fake scheme that
|
||||
// accepts all blocks as valid, without checking any consensus rules whatsoever.
|
||||
func NewFaker(db ethdb.Database) *XDPoS {
|
||||
// Set any missing consensus parameters to their defaults
|
||||
conf := params.TestXDPoSMockChainConfig.XDPoS
|
||||
|
||||
// Allocate the snapshot caches and create the engine
|
||||
BlockSigners, _ := lru.New(blockSignersCacheLimit)
|
||||
recents, _ := lru.NewARC(inmemorySnapshots)
|
||||
signatures, _ := lru.NewARC(inmemorySnapshots)
|
||||
validatorSignatures, _ := lru.NewARC(inmemorySnapshots)
|
||||
verifiedHeaders, _ := lru.NewARC(inmemorySnapshots)
|
||||
engine = &XDPoS{
|
||||
config: conf,
|
||||
db: db,
|
||||
BlockSigners: BlockSigners,
|
||||
recents: recents,
|
||||
signatures: signatures,
|
||||
verifiedHeaders: verifiedHeaders,
|
||||
validatorSignatures: validatorSignatures,
|
||||
proposals: make(map[common.Address]bool),
|
||||
}
|
||||
return engine
|
||||
}
|
||||
|
||||
func GetFaker() *XDPoS {
|
||||
return engine
|
||||
}
|
||||
|
||||
// Author implements consensus.Engine, returning the Ethereum address recovered
|
||||
// from the signature in the header's extra-data section.
|
||||
func (c *XDPoS) Author(header *types.Header) (common.Address, error) {
|
||||
|
|
@ -313,6 +344,10 @@ func (c *XDPoS) verifyHeaderWithCache(chain consensus.ChainReader, header *types
|
|||
// looking those up from the database. This is useful for concurrently verifying
|
||||
// a batch of new headers.
|
||||
func (c *XDPoS) verifyHeader(chain consensus.ChainReader, header *types.Header, parents []*types.Header, fullVerify bool) error {
|
||||
// If we're running a engine faking, accept any block as valid
|
||||
if c.config.SkipValidation {
|
||||
return nil
|
||||
}
|
||||
if common.IsTestnet {
|
||||
fullVerify = false
|
||||
}
|
||||
|
|
@ -1027,6 +1062,10 @@ func (c *XDPoS) CalcDifficulty(chain consensus.ChainReader, time uint64, parent
|
|||
}
|
||||
|
||||
func (c *XDPoS) calcDifficulty(chain consensus.ChainReader, parent *types.Header, signer common.Address) *big.Int {
|
||||
// If we're running a engine faking, skip calculation
|
||||
if c.config.SkipValidation {
|
||||
return big.NewInt(1)
|
||||
}
|
||||
len, preIndex, curIndex, _, err := c.YourTurn(chain, parent, signer)
|
||||
if err != nil {
|
||||
return big.NewInt(int64(len + curIndex - preIndex))
|
||||
|
|
|
|||
|
|
@ -151,7 +151,7 @@ type BlockChain struct {
|
|||
badBlocks *lru.Cache // Bad block cache
|
||||
shouldPreserve func(*types.Block) bool // Function used to determine whether should preserve the given block.
|
||||
IPCEndpoint string
|
||||
Client *ethclient.Client // Global ipc client instance.
|
||||
Client bind.ContractBackend // Global ipc client instance.
|
||||
}
|
||||
|
||||
// NewBlockChain returns a fully initialised block chain using information
|
||||
|
|
@ -1067,6 +1067,13 @@ func (bc *BlockChain) WriteBlockWithState(block *types.Block, receipts []*types.
|
|||
// Set new head.
|
||||
if status == CanonStatTy {
|
||||
bc.insert(block)
|
||||
// prepare set of masternodes for the next epoch
|
||||
if (block.NumberU64() % bc.chainConfig.XDPoS.Epoch) == (bc.chainConfig.XDPoS.Epoch - bc.chainConfig.XDPoS.Gap) {
|
||||
err := bc.UpdateM1()
|
||||
if err != nil {
|
||||
log.Crit("Error when update masternodes set. Stopping node", "err", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
// save cache BlockSigners
|
||||
if bc.chainConfig.XDPoS != nil && bc.chainConfig.IsTIPSigning(block.Number()) {
|
||||
|
|
@ -1283,13 +1290,6 @@ func (bc *BlockChain) insertChain(chain types.Blocks, verifySeals bool) (int, []
|
|||
if (chain[it.index].NumberU64() % bc.chainConfig.XDPoS.Epoch) == 0 {
|
||||
CheckpointCh <- 1
|
||||
}
|
||||
// prepare set of masternodes for the next epoch
|
||||
if (chain[it.index].NumberU64() % bc.chainConfig.XDPoS.Epoch) == (bc.chainConfig.XDPoS.Epoch - bc.chainConfig.XDPoS.Gap) {
|
||||
err := bc.UpdateM1()
|
||||
if err != nil {
|
||||
log.Crit("Error when update masternodes set. Stopping node", "err", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Any blocks remaining here? The only ones we care about are the future ones
|
||||
|
|
@ -1503,14 +1503,6 @@ func (bc *BlockChain) insertBlock(block *types.Block) ([]interface{}, []*types.L
|
|||
if (block.NumberU64() % bc.chainConfig.XDPoS.Epoch) == 0 {
|
||||
CheckpointCh <- 1
|
||||
}
|
||||
// prepare set of masternodes for the next epoch
|
||||
if (block.NumberU64() % bc.chainConfig.XDPoS.Epoch) == (bc.chainConfig.XDPoS.Epoch - bc.chainConfig.XDPoS.Gap) {
|
||||
err := bc.UpdateM1()
|
||||
if err != nil {
|
||||
log.Error("Error when update masternodes set. Stopping node", "err", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
}
|
||||
// Append a single chain head event if we've progressed the chain
|
||||
if status == CanonStatTy && bc.CurrentBlock().Hash() == block.Hash() {
|
||||
|
|
@ -1738,6 +1730,13 @@ func (bc *BlockChain) reorg(oldBlock, newBlock *types.Block) error {
|
|||
// Write lookup entries for hash based transaction/receipt searches
|
||||
rawdb.WriteTxLookupEntries(bc.db, newChain[i])
|
||||
addedTxs = append(addedTxs, newChain[i].Transactions()...)
|
||||
// prepare set of masternodes for the next epoch
|
||||
if (newChain[i].NumberU64() % bc.chainConfig.XDPoS.Epoch) == (bc.chainConfig.XDPoS.Epoch - bc.chainConfig.XDPoS.Gap) {
|
||||
err := bc.UpdateM1()
|
||||
if err != nil {
|
||||
log.Crit("Error when update masternodes set. Stopping node", "err", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
// When transactions get deleted from the database, the receipts that were
|
||||
// created in the fork must also be deleted
|
||||
|
|
@ -1989,7 +1988,7 @@ func (bc *BlockChain) SubscribeLogsEvent(ch chan<- []*types.Log) event.Subscript
|
|||
}
|
||||
|
||||
// Get current IPC Client.
|
||||
func (bc *BlockChain) GetClient() (*ethclient.Client, error) {
|
||||
func (bc *BlockChain) GetClient() (bind.ContractBackend, error) {
|
||||
if bc.Client == nil {
|
||||
// Inject ipc client global instance.
|
||||
client, err := ethclient.Dial(bc.IPCEndpoint)
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ import (
|
|||
"path/filepath"
|
||||
|
||||
"github.com/ethereum/go-ethereum/accounts"
|
||||
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/common/math"
|
||||
"github.com/ethereum/go-ethereum/consensus"
|
||||
|
|
@ -34,7 +35,6 @@ import (
|
|||
"github.com/ethereum/go-ethereum/core/vm"
|
||||
"github.com/ethereum/go-ethereum/eth/downloader"
|
||||
"github.com/ethereum/go-ethereum/eth/gasprice"
|
||||
"github.com/ethereum/go-ethereum/ethclient"
|
||||
"github.com/ethereum/go-ethereum/ethdb"
|
||||
"github.com/ethereum/go-ethereum/event"
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
|
|
@ -233,7 +233,7 @@ func (b *EthAPIBackend) ServiceFilter(ctx context.Context, session *bloombits.Ma
|
|||
}
|
||||
}
|
||||
|
||||
func (b *EthAPIBackend) GetIPCClient() (*ethclient.Client, error) {
|
||||
func (b *EthAPIBackend) GetIPCClient() (bind.ContractBackend, error) {
|
||||
client, err := b.eth.blockchain.GetClient()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ import (
|
|||
"math/big"
|
||||
|
||||
"github.com/ethereum/go-ethereum/accounts"
|
||||
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/consensus"
|
||||
"github.com/ethereum/go-ethereum/core"
|
||||
|
|
@ -29,7 +30,6 @@ import (
|
|||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/core/vm"
|
||||
"github.com/ethereum/go-ethereum/eth/downloader"
|
||||
"github.com/ethereum/go-ethereum/ethclient"
|
||||
"github.com/ethereum/go-ethereum/ethdb"
|
||||
"github.com/ethereum/go-ethereum/event"
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
|
|
@ -72,7 +72,7 @@ type Backend interface {
|
|||
|
||||
ChainConfig() *params.ChainConfig
|
||||
CurrentBlock() *types.Block
|
||||
GetIPCClient() (*ethclient.Client, error)
|
||||
GetIPCClient() (bind.ContractBackend, error)
|
||||
GetEngine() consensus.Engine
|
||||
GetRewardByHash(hash common.Hash) map[string]interface{}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ import (
|
|||
"path/filepath"
|
||||
|
||||
"github.com/ethereum/go-ethereum/accounts"
|
||||
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/common/math"
|
||||
"github.com/ethereum/go-ethereum/consensus"
|
||||
|
|
@ -35,7 +36,6 @@ import (
|
|||
"github.com/ethereum/go-ethereum/core/vm"
|
||||
"github.com/ethereum/go-ethereum/eth/downloader"
|
||||
"github.com/ethereum/go-ethereum/eth/gasprice"
|
||||
"github.com/ethereum/go-ethereum/ethclient"
|
||||
"github.com/ethereum/go-ethereum/ethdb"
|
||||
"github.com/ethereum/go-ethereum/event"
|
||||
"github.com/ethereum/go-ethereum/light"
|
||||
|
|
@ -210,7 +210,7 @@ func (b *LesApiBackend) ServiceFilter(ctx context.Context, session *bloombits.Ma
|
|||
}
|
||||
}
|
||||
|
||||
func (b *LesApiBackend) GetIPCClient() (*ethclient.Client, error) {
|
||||
func (b *LesApiBackend) GetIPCClient() (bind.ContractBackend, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -159,9 +159,10 @@ var (
|
|||
AllXDPoSProtocolChanges = &ChainConfig{big.NewInt(1337), big.NewInt(0), nil, false, big.NewInt(0), common.Hash{}, big.NewInt(0), big.NewInt(0), big.NewInt(0), nil, nil, nil, nil, nil, &XDPoSConfig{Period: 0, Epoch: 30000}}
|
||||
AllCliqueProtocolChanges = &ChainConfig{big.NewInt(1337), big.NewInt(0), nil, false, big.NewInt(0), common.Hash{}, big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), nil, nil, &CliqueConfig{Period: 0, Epoch: 30000}, nil}
|
||||
|
||||
TestChainConfig = &ChainConfig{big.NewInt(1), big.NewInt(0), nil, false, big.NewInt(0), common.Hash{}, big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), nil, new(EthashConfig), nil, nil}
|
||||
TestRules = TestChainConfig.Rules(new(big.Int))
|
||||
TestXDPoSChainConfig = &ChainConfig{big.NewInt(1337), big.NewInt(0), nil, false, big.NewInt(0), common.Hash{}, big.NewInt(0), big.NewInt(0), big.NewInt(0), nil, nil, nil, nil, nil, &XDPoSConfig{Period: 2, Epoch: 900, Reward: 250, RewardCheckpoint: 900, Gap: 890, FoudationWalletAddr: common.HexToAddress("0x0000000000000000000000000000000000000068")}}
|
||||
TestXDPoSMockChainConfig = &ChainConfig{big.NewInt(1337), big.NewInt(0), nil, false, big.NewInt(0), common.Hash{}, big.NewInt(0), big.NewInt(0), big.NewInt(0), nil, nil, nil, nil, nil, &XDPoSConfig{Epoch: 900, Gap: 890, SkipValidation: true}}
|
||||
TestChainConfig = &ChainConfig{big.NewInt(1), big.NewInt(0), nil, false, big.NewInt(0), common.Hash{}, big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), nil, new(EthashConfig), nil, nil}
|
||||
TestRules = TestChainConfig.Rules(new(big.Int))
|
||||
TestXDPoSChainConfig = &ChainConfig{big.NewInt(1337), big.NewInt(0), nil, false, big.NewInt(0), common.Hash{}, big.NewInt(0), big.NewInt(0), big.NewInt(0), nil, nil, nil, nil, nil, &XDPoSConfig{Period: 2, Epoch: 900, Reward: 250, RewardCheckpoint: 900, Gap: 890, FoudationWalletAddr: common.HexToAddress("0x0000000000000000000000000000000000000068")}}
|
||||
)
|
||||
|
||||
// TrustedCheckpoint represents a set of post-processed trie roots (CHT and
|
||||
|
|
@ -234,6 +235,7 @@ type XDPoSConfig struct {
|
|||
RewardCheckpoint uint64 `json:"rewardCheckpoint"` // Checkpoint block for calculate rewards.
|
||||
Gap uint64 `json:"gap"` // Gap time preparing for the next epoch
|
||||
FoudationWalletAddr common.Address `json:"foudationWalletAddr"` // Foundation Address Wallet
|
||||
SkipValidation bool //Skip Block Validation for testing purpose
|
||||
}
|
||||
|
||||
// String implements the stringer interface, returning the consensus engine details.
|
||||
|
|
|
|||
483
tests/end_to_end/block_signer_test.go
Normal file
483
tests/end_to_end/block_signer_test.go
Normal file
|
|
@ -0,0 +1,483 @@
|
|||
package end_to_end
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"math/big"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
||||
"github.com/ethereum/go-ethereum/accounts/abi/bind/backends"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/consensus/XDPoS"
|
||||
contractValidator "github.com/ethereum/go-ethereum/contracts/validator/contract"
|
||||
"github.com/ethereum/go-ethereum/core"
|
||||
. "github.com/ethereum/go-ethereum/core"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/core/vm"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
"github.com/ethereum/go-ethereum/rlp"
|
||||
)
|
||||
|
||||
type masterNodes map[string]big.Int
|
||||
type signersList map[string]bool
|
||||
|
||||
var (
|
||||
acc1Key, _ = crypto.HexToECDSA("8a1f9a8f95be41cd7ccb6168179afb4504aefe388d1e14474d32c45c72ce7b7a")
|
||||
acc2Key, _ = crypto.HexToECDSA("49a7b37aa6f6645917e7b807e9d1c00d4fa71f18343b0d4122a4d2df64dd6fee")
|
||||
acc3Key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
|
||||
voterKey, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee04aefe388d1e14474d32c45c72ce7b7a")
|
||||
acc1Addr = crypto.PubkeyToAddress(acc1Key.PublicKey) //xdc703c4b2bD70c169f5717101CaeE543299Fc946C7
|
||||
acc2Addr = crypto.PubkeyToAddress(acc2Key.PublicKey) //xdc0D3ab14BBaD3D99F4203bd7a11aCB94882050E7e
|
||||
acc3Addr = crypto.PubkeyToAddress(acc3Key.PublicKey) //xdc71562b71999873DB5b286dF957af199Ec94617F7
|
||||
voterAddr = crypto.PubkeyToAddress(voterKey.PublicKey) //xdc5F74529C0338546f82389402a01c31fB52c6f434
|
||||
chainID = int64(1337)
|
||||
)
|
||||
|
||||
func debugMessage(backend *backends.SimulatedBackend, signers signersList, t *testing.T) {
|
||||
ms := GetCandidateFromCurrentSmartContract(backend, t)
|
||||
fmt.Println("=== current smart contract")
|
||||
for nodeAddr, cap := range ms {
|
||||
if !strings.Contains(nodeAddr, "000000000000000000000000000000000000") { //remove defaults
|
||||
fmt.Println(nodeAddr, cap)
|
||||
}
|
||||
}
|
||||
fmt.Println("=== this block signer list")
|
||||
for signer := range signers {
|
||||
if !strings.Contains(signer, "000000000000000000000000000000000000") { //remove defaults
|
||||
fmt.Println(signer)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func getCommonBackend(t *testing.T) *backends.SimulatedBackend {
|
||||
|
||||
// initial helper backend
|
||||
contractBackendForSC := backends.NewXDCSimulatedBackend(core.GenesisAlloc{
|
||||
voterAddr: {Balance: new(big.Int).SetUint64(10000000000)},
|
||||
})
|
||||
|
||||
transactOpts := bind.NewKeyedTransactor(voterKey)
|
||||
|
||||
var candidates []common.Address
|
||||
var caps []*big.Int
|
||||
defalutCap := new(big.Int)
|
||||
defalutCap.SetString("1000000000", 10)
|
||||
|
||||
for i := 1; i <= 16; i++ {
|
||||
addr := fmt.Sprintf("%02d", i)
|
||||
candidates = append(candidates, common.StringToAddress(addr))
|
||||
caps = append(caps, defalutCap)
|
||||
}
|
||||
|
||||
acc1Cap, acc2Cap, acc3Cap, voterCap := new(big.Int), new(big.Int), new(big.Int), new(big.Int)
|
||||
|
||||
acc1Cap.SetString("10000001", 10)
|
||||
acc2Cap.SetString("10000002", 10)
|
||||
acc3Cap.SetString("10000003", 10)
|
||||
voterCap.SetString("1000000000", 10)
|
||||
|
||||
caps = append(caps, voterCap, acc1Cap, acc2Cap, acc3Cap)
|
||||
candidates = append(candidates, voterAddr, acc1Addr, acc2Addr, acc3Addr)
|
||||
// create validator smart contract
|
||||
validatorSCAddr, _, _, err := contractValidator.DeployXDCValidator(
|
||||
transactOpts,
|
||||
contractBackendForSC,
|
||||
candidates,
|
||||
caps,
|
||||
voterAddr, // first owner, not used
|
||||
big.NewInt(50000),
|
||||
big.NewInt(1),
|
||||
big.NewInt(99),
|
||||
big.NewInt(100),
|
||||
big.NewInt(100),
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatalf("can't deploy root registry: %v", err)
|
||||
}
|
||||
|
||||
contractBackendForSC.Commit() // Write into database(state)
|
||||
|
||||
// Prepare Code and Storage
|
||||
d := time.Now().Add(1000 * time.Millisecond)
|
||||
ctx, cancel := context.WithDeadline(context.Background(), d)
|
||||
defer cancel()
|
||||
|
||||
code, _ := contractBackendForSC.CodeAt(ctx, validatorSCAddr, nil)
|
||||
storage := make(map[common.Hash]common.Hash)
|
||||
f := func(key, val common.Hash) bool {
|
||||
decode := []byte{}
|
||||
trim := bytes.TrimLeft(val.Bytes(), "\x00")
|
||||
rlp.DecodeBytes(trim, &decode)
|
||||
storage[key] = common.BytesToHash(decode)
|
||||
log.Info("DecodeBytes", "value", val.String(), "decode", storage[key].String())
|
||||
return true
|
||||
}
|
||||
contractBackendForSC.ForEachStorageAt(ctx, validatorSCAddr, nil, f)
|
||||
|
||||
// create test backend with smart contract in it
|
||||
contractBackend2 := backends.NewXDCSimulatedBackend(core.GenesisAlloc{
|
||||
acc1Addr: {Balance: new(big.Int).SetUint64(10000000000)},
|
||||
acc2Addr: {Balance: new(big.Int).SetUint64(10000000000)},
|
||||
acc3Addr: {Balance: new(big.Int).SetUint64(10000000000)},
|
||||
voterAddr: {Balance: new(big.Int).SetUint64(10000000000)},
|
||||
common.HexToAddress(common.MasternodeVotingSMC): {Balance: new(big.Int).SetUint64(1), Code: code, Storage: storage}, // Binding the MasternodeVotingSMC with newly created 'code' for SC execution
|
||||
})
|
||||
|
||||
return contractBackend2
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
func transferTx(t *testing.T) *types.Transaction {
|
||||
data := []byte{}
|
||||
gasPrice := big.NewInt(int64(1))
|
||||
gasLimit := uint64(21000)
|
||||
amount := big.NewInt(int64(999))
|
||||
nonce := uint64(0)
|
||||
to := common.HexToAddress("35658f7b2a9E7701e65E7a654659eb1C481d1dC5")
|
||||
tx := types.NewTransaction(nonce, to, amount, gasLimit, gasPrice, data)
|
||||
signedTX, err := types.SignTx(tx, types.NewEIP155Signer(big.NewInt(chainID)), acc4Key)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
return signedTX
|
||||
}
|
||||
func proposeTX(t *testing.T) *types.Transaction {
|
||||
data := common.Hex2Bytes("012679510000000000000000000000000d3ab14bbad3d99f4203bd7a11acb94882050e7e")
|
||||
//data := []byte{}
|
||||
fmt.Println("data", string(data[:]))
|
||||
gasPrice := big.NewInt(int64(0))
|
||||
gasLimit := uint64(22680)
|
||||
amountInt := new(big.Int)
|
||||
amount, ok := amountInt.SetString("11000000000000000000000000", 10)
|
||||
if !ok {
|
||||
t.Fatal("big int init failed")
|
||||
}
|
||||
nonce := uint64(0)
|
||||
to := common.HexToAddress("xdc35658f7b2a9e7701e65e7a654659eb1c481d1dc5")
|
||||
tx := types.NewTransaction(nonce, to, amount, gasLimit, gasPrice, data)
|
||||
signedTX, err := types.SignTx(tx, types.NewEIP155Signer(big.NewInt(chainID)), acc4Key)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
return signedTX
|
||||
}
|
||||
*/
|
||||
|
||||
func voteTX(gasLimit uint64, nonce uint64, addr string) (*types.Transaction, error) {
|
||||
vote := "6dd7d8ea" // VoteMethod = "0x6dd7d8ea"
|
||||
action := fmt.Sprintf("%s%s%s", vote, "000000000000000000000000", addr[3:])
|
||||
data := common.Hex2Bytes(action)
|
||||
gasPrice := big.NewInt(int64(0))
|
||||
amountInt := new(big.Int)
|
||||
amount, ok := amountInt.SetString("60000", 10)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("big int init failed")
|
||||
}
|
||||
to := common.HexToAddress(common.MasternodeVotingSMC)
|
||||
tx := types.NewTransaction(nonce, to, amount, gasLimit, gasPrice, data)
|
||||
|
||||
signedTX, err := types.SignTx(tx, types.NewEIP155Signer(big.NewInt(chainID)), voterKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return signedTX, nil
|
||||
}
|
||||
func UpdateSigner(bc *BlockChain) error {
|
||||
err := bc.UpdateM1()
|
||||
return err
|
||||
}
|
||||
|
||||
func GetSnapshotSigner(bc *BlockChain, header *types.Header) (signersList, error) {
|
||||
engine := bc.Engine().(*XDPoS.XDPoS)
|
||||
snap, err := engine.GetSnapshot(bc, header)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
}
|
||||
ms := make(signersList)
|
||||
|
||||
for addr := range snap.Signers {
|
||||
ms[addr.Hex()] = true
|
||||
}
|
||||
return ms, nil
|
||||
|
||||
}
|
||||
|
||||
func GetCandidateFromCurrentSmartContract(backend bind.ContractBackend, t *testing.T) masterNodes {
|
||||
addr := common.HexToAddress(common.MasternodeVotingSMC)
|
||||
validator, err := contractValidator.NewXDCValidator(addr, backend)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
opts := new(bind.CallOpts)
|
||||
candidates, err := validator.GetCandidates(opts)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
ms := make(masterNodes)
|
||||
for _, candidate := range candidates {
|
||||
v, err := validator.GetCandidateCap(opts, candidate)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
ms[candidate.String()] = *v
|
||||
}
|
||||
return ms
|
||||
}
|
||||
|
||||
func PrepareXDCTestBlockChain(t *testing.T) (*BlockChain, *backends.SimulatedBackend, *types.Block) {
|
||||
// Preparation
|
||||
var err error
|
||||
backend := getCommonBackend(t)
|
||||
blockchain := backend.GetBlockChain()
|
||||
blockchain.Client = backend
|
||||
|
||||
currentBlock := blockchain.Genesis()
|
||||
|
||||
// Insert initial 9 blocks
|
||||
for i := 1; i <= 9; i++ {
|
||||
blockCoinBase := fmt.Sprintf("0x111000000000000000000000000000000%03d", i)
|
||||
merkleRoot := "35999dded35e8db12de7e6c1471eb9670c162eec616ecebbaf4fddd4676fb930"
|
||||
block, err := insertBlock(blockchain, i, blockCoinBase, currentBlock, merkleRoot)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
currentBlock = block
|
||||
}
|
||||
// Update Signer as there is no previous signer assigned
|
||||
err = UpdateSigner(blockchain)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
return blockchain, backend, currentBlock
|
||||
}
|
||||
|
||||
//Should call updateM1 at gap block, and update the snapshot if there are SM transactions involved
|
||||
func TestCallUpdateM1WithSmartContractTranscation(t *testing.T) {
|
||||
|
||||
blockchain, backend, currentBlock := PrepareXDCTestBlockChain(t)
|
||||
// Insert first Block 10 A
|
||||
t.Logf("Inserting block with propose at 10 A...")
|
||||
blockCoinbaseA := "0xaaa0000000000000000000000000000000000010"
|
||||
tx, err := voteTX(37117, 0, acc1Addr.String())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
//Get from block validator error message
|
||||
merkleRoot := "46234e9cd7e85a267f7f0435b15256a794a2f6d65cc98cdbd21dcd10a01d9772"
|
||||
blockA, err := insertBlockTxs(blockchain, 10, blockCoinbaseA, currentBlock, []*types.Transaction{tx}, merkleRoot)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
signers, err := GetSnapshotSigner(blockchain, blockA.Header())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if signers[acc1Addr.Hex()] != true {
|
||||
debugMessage(backend, signers, t)
|
||||
t.Fatalf("account 1 should sit in the signer list")
|
||||
}
|
||||
}
|
||||
|
||||
// Should have previous smart contract transcation, then have 2 blocks at Gap Step.
|
||||
// Both Block should have update signer whenever they be added into main chain.
|
||||
|
||||
func Test1(t *testing.T) {
|
||||
}
|
||||
|
||||
// Should call updateM1 and update snapshot when a forked block(at gap block number) is inserted back into main chain (Edge case)
|
||||
func TestCallUpdateM1WhenForkedBlockBackToMainChain(t *testing.T) {
|
||||
|
||||
blockchain, backend, currentBlock := PrepareXDCTestBlockChain(t)
|
||||
|
||||
// Check initial signer
|
||||
signers, err := GetSnapshotSigner(blockchain, blockchain.CurrentBlock().Header())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if signers[acc3Addr.Hex()] != true {
|
||||
debugMessage(backend, signers, t)
|
||||
t.Fatalf("voterAddr should sit in the signer list")
|
||||
}
|
||||
|
||||
// Insert first Block 10 A
|
||||
t.Logf("Inserting block with propose at 10 A...")
|
||||
blockCoinbaseA := "0xaaa0000000000000000000000000000000000010"
|
||||
tx, err := voteTX(37117, 0, acc1Addr.String())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
merkleRoot := "46234e9cd7e85a267f7f0435b15256a794a2f6d65cc98cdbd21dcd10a01d9772"
|
||||
blockA, err := insertBlockTxs(blockchain, 10, blockCoinbaseA, currentBlock, []*types.Transaction{tx}, merkleRoot)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
signers, err = GetSnapshotSigner(blockchain, blockA.Header())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if signers[acc1Addr.Hex()] != true {
|
||||
debugMessage(backend, signers, t)
|
||||
t.Fatalf("account 1 should sit in the signer list")
|
||||
}
|
||||
|
||||
// Insert forked Block 10 B
|
||||
t.Logf("Inserting block with propose at 10 B...")
|
||||
|
||||
blockCoinBase10B := "0xbbb0000000000000000000000000000000000010"
|
||||
tx, err = voteTX(37117, 0, acc2Addr.String())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
merkleRoot = "068dfa09d7b4093441c0cc4d9807a71bc586f6101c072d939b214c21cd136eb3"
|
||||
block10B, err := insertBlockTxs(blockchain, 10, blockCoinBase10B, currentBlock, []*types.Transaction{tx}, merkleRoot)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
signers, err = GetSnapshotSigner(blockchain, block10B.Header())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
// Should not run the `updateM1` for forked chain, hence account3 still exit
|
||||
if signers[acc3Addr.Hex()] != true {
|
||||
debugMessage(backend, signers, t)
|
||||
t.Fatalf("account 3 should sit in the signer list as previos block result")
|
||||
}
|
||||
|
||||
//Insert block 11 parent is 11 B
|
||||
t.Logf("Inserting block with propose at 11 B...")
|
||||
|
||||
blockCoinBase11B := "0xbbb0000000000000000000000000000000000011"
|
||||
merkleRoot = "068dfa09d7b4093441c0cc4d9807a71bc586f6101c072d939b214c21cd136eb3"
|
||||
block11B, err := insertBlock(blockchain, 11, blockCoinBase11B, block10B, merkleRoot)
|
||||
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
signers, err = GetSnapshotSigner(blockchain, block10B.Header())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if signers[acc2Addr.Hex()] != true {
|
||||
debugMessage(backend, signers, t)
|
||||
t.Fatalf("account 2 should sit in the signer list")
|
||||
}
|
||||
|
||||
signers, err = GetSnapshotSigner(blockchain, block11B.Header())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if signers[acc2Addr.Hex()] != true {
|
||||
debugMessage(backend, signers, t)
|
||||
t.Fatalf("account 2 should sit in the signer list")
|
||||
}
|
||||
|
||||
signers, err = GetSnapshotSigner(blockchain, blockchain.CurrentBlock().Header())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if signers[acc2Addr.Hex()] != true {
|
||||
debugMessage(backend, signers, t)
|
||||
t.Fatalf("acc2Addr should sit in the signer list")
|
||||
}
|
||||
}
|
||||
|
||||
// insert Block without transcation attached
|
||||
func insertBlock(blockchain *BlockChain, blockNum int, blockCoinBase string, parentBlock *types.Block, root string) (*types.Block, error) {
|
||||
block, err := createXDPoSTestBlock(
|
||||
blockchain,
|
||||
parentBlock.Hash().Hex(),
|
||||
blockCoinBase, blockNum, nil,
|
||||
"56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
|
||||
common.HexToHash(root),
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = blockchain.InsertBlock(block)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return block, nil
|
||||
}
|
||||
|
||||
// insert Block with transcation attached
|
||||
func insertBlockTxs(blockchain *BlockChain, blockNum int, blockCoinBase string, parentBlock *types.Block, txs []*types.Transaction, root string) (*types.Block, error) {
|
||||
block, err := createXDPoSTestBlock(
|
||||
blockchain,
|
||||
parentBlock.Hash().Hex(),
|
||||
blockCoinBase, blockNum, txs,
|
||||
"9319777b782ba2c83a33c995481ff894ac96d9a92a1963091346a3e1e386705c",
|
||||
common.HexToHash(root),
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = blockchain.InsertBlock(block)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return block, nil
|
||||
}
|
||||
|
||||
func createXDPoSTestBlock(bc *BlockChain, parentHash, coinbase string, number int, txs []*types.Transaction, receiptHash string, root common.Hash) (*types.Block, error) {
|
||||
extraSubstring := "d7830100018358444388676f312e31342e31856c696e75780000000000000000b185dc0d0e917d18e5dbf0746be6597d3331dd27ea0554e6db433feb2e81730b20b2807d33a1527bf43cd3bc057aa7f641609c2551ebe2fd575f4db704fbf38101" // Grabbed from existing mainnet block, it does not have any meaning except for the length validation
|
||||
//ReceiptHash = "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421"
|
||||
//Root := "0xc99c095e53ff1afe3b86750affd13c7550a2d24d51fb8e41b3c3ef2ea8274bcc"
|
||||
extraByte, _ := hex.DecodeString(extraSubstring)
|
||||
header := types.Header{
|
||||
ParentHash: common.HexToHash(parentHash),
|
||||
UncleHash: types.EmptyUncleHash,
|
||||
TxHash: types.EmptyRootHash,
|
||||
ReceiptHash: types.EmptyRootHash,
|
||||
Root: root,
|
||||
Coinbase: common.HexToAddress(coinbase),
|
||||
Difficulty: big.NewInt(int64(1)),
|
||||
Number: big.NewInt(int64(number)),
|
||||
GasLimit: 1200000000,
|
||||
Time: big.NewInt(int64(number * 10)),
|
||||
Extra: extraByte,
|
||||
}
|
||||
|
||||
var block *types.Block
|
||||
if len(txs) == 0 {
|
||||
block = types.NewBlockWithHeader(&header)
|
||||
} else {
|
||||
|
||||
// Prepare Receipt
|
||||
statedb, err := bc.StateAt(bc.GetBlockByNumber(uint64(number - 1)).Root()) //Get parent root
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("%v when get state", err)
|
||||
}
|
||||
gp := new(GasPool).AddGas(header.GasLimit)
|
||||
usedGas := uint64(0)
|
||||
statedb.Prepare(txs[0].Hash(), header.Hash(), 0)
|
||||
receipt, _, err := ApplyTransaction(bc.Config(), bc, &header.Coinbase, gp, statedb, &header, txs[0], &usedGas, vm.Config{})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("%v when creating block", err)
|
||||
}
|
||||
header.GasUsed = txs[0].Gas()
|
||||
block = types.NewBlock(&header, txs, nil, []*types.Receipt{receipt})
|
||||
}
|
||||
|
||||
return block, nil
|
||||
}
|
||||
Loading…
Reference in a new issue