Merge pull request #12 from hash-laboratories-au/adaptor-config-setup-with-tests

Adaptor config setup with tests
This commit is contained in:
Jerome 2021-10-17 12:57:33 +11:00 committed by GitHub
commit a996c3a1a3
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
23 changed files with 900 additions and 31233 deletions

View file

@ -70,18 +70,18 @@ type SimulatedBackend struct {
} }
// XDC simulated backend for testing purpose. // XDC simulated backend for testing purpose.
func NewXDCSimulatedBackend(alloc core.GenesisAlloc, gasLimit uint64) *SimulatedBackend { func NewXDCSimulatedBackend(alloc core.GenesisAlloc, gasLimit uint64, chainConfig *params.ChainConfig) *SimulatedBackend {
// database := ethdb.NewMemDatabase() // database := ethdb.NewMemDatabase()
database := rawdb.NewMemoryDatabase() database := rawdb.NewMemoryDatabase()
genesis := core.Genesis{ genesis := core.Genesis{
GasLimit: gasLimit, // need this big, support initial smart contract GasLimit: gasLimit, // need this big, support initial smart contract
Config: params.TestXDPoSMockChainConfig, Config: chainConfig,
Alloc: alloc, Alloc: alloc,
ExtraData: append(make([]byte, 32), make([]byte, 65)...), ExtraData: append(make([]byte, 32), make([]byte, 65)...),
} }
genesis.MustCommit(database) genesis.MustCommit(database)
consensus := XDPoS.NewFaker(database) consensus := XDPoS.NewFaker(database, chainConfig)
// Attach mock trading and lending service // Attach mock trading and lending service
var DefaultConfig = XDCx.Config{ var DefaultConfig = XDCx.Config{

View file

@ -27,6 +27,7 @@ import (
"testing" "testing"
"github.com/XinFinOrg/XDPoSChain/common" "github.com/XinFinOrg/XDPoSChain/common"
"github.com/XinFinOrg/XDPoSChain/params"
"golang.org/x/tools/imports" "golang.org/x/tools/imports"
) )
@ -229,7 +230,7 @@ var bindTests = []struct {
// Generate a new random account and a funded simulator // Generate a new random account and a funded simulator
key, _ := crypto.GenerateKey() key, _ := crypto.GenerateKey()
auth := bind.NewKeyedTransactor(key) auth := bind.NewKeyedTransactor(key)
sim := backends.NewXDCSimulatedBackend(core.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000)}}, 10000000) sim := backends.NewXDCSimulatedBackend(core.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000)}}, 10000000, params.TestXDPoSMockChainConfig)
// Deploy an interaction tester contract and call a transaction on it // Deploy an interaction tester contract and call a transaction on it
_, _, interactor, err := DeployInteractor(auth, sim, "Deploy string") _, _, interactor, err := DeployInteractor(auth, sim, "Deploy string")
@ -270,7 +271,7 @@ var bindTests = []struct {
// Generate a new random account and a funded simulator // Generate a new random account and a funded simulator
key, _ := crypto.GenerateKey() key, _ := crypto.GenerateKey()
auth := bind.NewKeyedTransactor(key) auth := bind.NewKeyedTransactor(key)
sim := backends.NewXDCSimulatedBackend(core.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000)}}, 10000000) sim := backends.NewXDCSimulatedBackend(core.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000)}}, 10000000, params.TestXDPoSMockChainConfig)
// Deploy a tuple tester contract and execute a structured call on it // Deploy a tuple tester contract and execute a structured call on it
_, _, getter, err := DeployGetter(auth, sim) _, _, getter, err := DeployGetter(auth, sim)
@ -302,7 +303,7 @@ var bindTests = []struct {
// Generate a new random account and a funded simulator // Generate a new random account and a funded simulator
key, _ := crypto.GenerateKey() key, _ := crypto.GenerateKey()
auth := bind.NewKeyedTransactor(key) auth := bind.NewKeyedTransactor(key)
sim := backends.NewXDCSimulatedBackend(core.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000)}}, 10000000) sim := backends.NewXDCSimulatedBackend(core.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000)}}, 10000000, params.TestXDPoSMockChainConfig)
// Deploy a tuple tester contract and execute a structured call on it // Deploy a tuple tester contract and execute a structured call on it
_, _, tupler, err := DeployTupler(auth, sim) _, _, tupler, err := DeployTupler(auth, sim)
@ -344,7 +345,7 @@ var bindTests = []struct {
// Generate a new random account and a funded simulator // Generate a new random account and a funded simulator
key, _ := crypto.GenerateKey() key, _ := crypto.GenerateKey()
auth := bind.NewKeyedTransactor(key) auth := bind.NewKeyedTransactor(key)
sim := backends.NewXDCSimulatedBackend(core.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000)}}, 10000000) sim := backends.NewXDCSimulatedBackend(core.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000)}}, 10000000, params.TestXDPoSMockChainConfig)
// Deploy a slice tester contract and execute a n array call on it // Deploy a slice tester contract and execute a n array call on it
_, _, slicer, err := DeploySlicer(auth, sim) _, _, slicer, err := DeploySlicer(auth, sim)
@ -378,7 +379,7 @@ var bindTests = []struct {
// Generate a new random account and a funded simulator // Generate a new random account and a funded simulator
key, _ := crypto.GenerateKey() key, _ := crypto.GenerateKey()
auth := bind.NewKeyedTransactor(key) auth := bind.NewKeyedTransactor(key)
sim := backends.NewXDCSimulatedBackend(core.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000)}}, 10000000) sim := backends.NewXDCSimulatedBackend(core.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000)}}, 10000000, params.TestXDPoSMockChainConfig)
// Deploy a default method invoker contract and execute its default method // Deploy a default method invoker contract and execute its default method
_, _, defaulter, err := DeployDefaulter(auth, sim) _, _, defaulter, err := DeployDefaulter(auth, sim)
@ -411,7 +412,7 @@ var bindTests = []struct {
`[{"constant":true,"inputs":[],"name":"String","outputs":[{"name":"","type":"string"}],"type":"function"}]`, `[{"constant":true,"inputs":[],"name":"String","outputs":[{"name":"","type":"string"}],"type":"function"}]`,
` `
// Create a simulator and wrap a non-deployed contract // Create a simulator and wrap a non-deployed contract
sim := backends.NewXDCSimulatedBackend(nil, uint64(10000000000)) sim := backends.NewXDCSimulatedBackend(nil, uint64(10000000000), params.TestXDPoSMockChainConfig)
nonexistent, err := NewNonExistent(common.Address{}, sim) nonexistent, err := NewNonExistent(common.Address{}, sim)
if err != nil { if err != nil {
@ -447,7 +448,7 @@ var bindTests = []struct {
// Generate a new random account and a funded simulator // Generate a new random account and a funded simulator
key, _ := crypto.GenerateKey() key, _ := crypto.GenerateKey()
auth := bind.NewKeyedTransactor(key) auth := bind.NewKeyedTransactor(key)
sim := backends.NewXDCSimulatedBackend(core.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000)}}, 10000000) sim := backends.NewXDCSimulatedBackend(core.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000)}}, 10000000, params.TestXDPoSMockChainConfig)
// Deploy a funky gas pattern contract // Deploy a funky gas pattern contract
_, _, limiter, err := DeployFunkyGasPattern(auth, sim) _, _, limiter, err := DeployFunkyGasPattern(auth, sim)
@ -482,7 +483,7 @@ var bindTests = []struct {
// Generate a new random account and a funded simulator // Generate a new random account and a funded simulator
key, _ := crypto.GenerateKey() key, _ := crypto.GenerateKey()
auth := bind.NewKeyedTransactor(key) auth := bind.NewKeyedTransactor(key)
sim := backends.NewXDCSimulatedBackend(core.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000)}}, 10000000) sim := backends.NewXDCSimulatedBackend(core.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000)}}, 10000000, params.TestXDPoSMockChainConfig)
// Deploy a sender tester contract and execute a structured call on it // Deploy a sender tester contract and execute a structured call on it
_, _, callfrom, err := DeployCallFrom(auth, sim) _, _, callfrom, err := DeployCallFrom(auth, sim)
@ -542,7 +543,7 @@ var bindTests = []struct {
// Generate a new random account and a funded simulator // Generate a new random account and a funded simulator
key, _ := crypto.GenerateKey() key, _ := crypto.GenerateKey()
auth := bind.NewKeyedTransactor(key) auth := bind.NewKeyedTransactor(key)
sim := backends.NewXDCSimulatedBackend(core.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000)}}, 10000000) sim := backends.NewXDCSimulatedBackend(core.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000)}}, 10000000, params.TestXDPoSMockChainConfig)
// Deploy a underscorer tester contract and execute a structured call on it // Deploy a underscorer tester contract and execute a structured call on it
_, _, underscorer, err := DeployUnderscorer(auth, sim) _, _, underscorer, err := DeployUnderscorer(auth, sim)
@ -612,7 +613,7 @@ var bindTests = []struct {
// Generate a new random account and a funded simulator // Generate a new random account and a funded simulator
key, _ := crypto.GenerateKey() key, _ := crypto.GenerateKey()
auth := bind.NewKeyedTransactor(key) auth := bind.NewKeyedTransactor(key)
sim := backends.NewXDCSimulatedBackend(core.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000)}}, 10000000) sim := backends.NewXDCSimulatedBackend(core.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000)}}, 10000000, params.TestXDPoSMockChainConfig)
// Deploy an eventer contract // Deploy an eventer contract
_, _, eventer, err := DeployEventer(auth, sim) _, _, eventer, err := DeployEventer(auth, sim)
@ -761,7 +762,7 @@ var bindTests = []struct {
// Generate a new random account and a funded simulator // Generate a new random account and a funded simulator
key, _ := crypto.GenerateKey() key, _ := crypto.GenerateKey()
auth := bind.NewKeyedTransactor(key) auth := bind.NewKeyedTransactor(key)
sim := backends.NewXDCSimulatedBackend(core.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000)}}, 10000000) sim := backends.NewXDCSimulatedBackend(core.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000)}}, 10000000, params.TestXDPoSMockChainConfig)
//deploy the test contract //deploy the test contract
_, _, testContract, err := DeployDeeplyNestedArray(auth, sim) _, _, testContract, err := DeployDeeplyNestedArray(auth, sim)
@ -819,6 +820,7 @@ func TestBindings(t *testing.T) {
if !common.FileExist(gocmd) { if !common.FileExist(gocmd) {
t.Skip("go sdk not found for testing") t.Skip("go sdk not found for testing")
} }
t.Log("Using config", params.TestXDPoSMockChainConfig)
// Skip the test if the go-ethereum sources are symlinked (https://github.com/golang/go/issues/14845) // Skip the test if the go-ethereum sources are symlinked (https://github.com/golang/go/issues/14845)
linkTestCode := fmt.Sprintf("package linktest\nfunc CheckSymlinks(){\nfmt.Println(backends.NewSimulatedBackend(nil))\n}") linkTestCode := fmt.Sprintf("package linktest\nfunc CheckSymlinks(){\nfmt.Println(backends.NewSimulatedBackend(nil))\n}")
linkTestDeps, err := imports.Process(os.TempDir(), []byte(linkTestCode), nil) linkTestDeps, err := imports.Process(os.TempDir(), []byte(linkTestCode), nil)

View file

@ -28,6 +28,7 @@ import (
"github.com/XinFinOrg/XDPoSChain/core" "github.com/XinFinOrg/XDPoSChain/core"
"github.com/XinFinOrg/XDPoSChain/core/types" "github.com/XinFinOrg/XDPoSChain/core/types"
"github.com/XinFinOrg/XDPoSChain/crypto" "github.com/XinFinOrg/XDPoSChain/crypto"
"github.com/XinFinOrg/XDPoSChain/params"
) )
var testKey, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") var testKey, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
@ -56,7 +57,7 @@ func TestWaitDeployed(t *testing.T) {
backend := backends.NewXDCSimulatedBackend( backend := backends.NewXDCSimulatedBackend(
core.GenesisAlloc{ core.GenesisAlloc{
crypto.PubkeyToAddress(testKey.PublicKey): {Balance: big.NewInt(10000000000)}, crypto.PubkeyToAddress(testKey.PublicKey): {Balance: big.NewInt(10000000000)},
}, 10000000, }, 10000000, params.TestXDPoSMockChainConfig,
) )
// Create the transaction. // Create the transaction.

View file

@ -177,7 +177,7 @@ func (w *wizard) makeGenesis() {
// Validator Smart Contract Code // Validator Smart Contract Code
pKey, _ := crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") pKey, _ := crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
addr := crypto.PubkeyToAddress(pKey.PublicKey) addr := crypto.PubkeyToAddress(pKey.PublicKey)
contractBackend := backends.NewXDCSimulatedBackend(core.GenesisAlloc{addr: {Balance: big.NewInt(1000000000)}}, 10000000) contractBackend := backends.NewXDCSimulatedBackend(core.GenesisAlloc{addr: {Balance: big.NewInt(1000000000)}}, 10000000, params.TestXDPoSMockChainConfig)
transactOpts := bind.NewKeyedTransactor(pKey) transactOpts := bind.NewKeyedTransactor(pKey)
validatorAddress, _, err := validatorContract.DeployValidator(transactOpts, contractBackend, signers, validatorCaps, owner) validatorAddress, _, err := validatorContract.DeployValidator(transactOpts, contractBackend, signers, validatorCaps, owner)

View file

@ -22,7 +22,9 @@ import (
"github.com/XinFinOrg/XDPoSChain/common" "github.com/XinFinOrg/XDPoSChain/common"
"github.com/XinFinOrg/XDPoSChain/consensus" "github.com/XinFinOrg/XDPoSChain/consensus"
"github.com/XinFinOrg/XDPoSChain/consensus/XDPoS/engines/engine_v1" "github.com/XinFinOrg/XDPoSChain/consensus/XDPoS/engines/engine_v1"
"github.com/XinFinOrg/XDPoSChain/consensus/XDPoS/engines/engine_v2"
"github.com/XinFinOrg/XDPoSChain/consensus/XDPoS/utils" "github.com/XinFinOrg/XDPoSChain/consensus/XDPoS/utils"
"github.com/XinFinOrg/XDPoSChain/consensus/clique" "github.com/XinFinOrg/XDPoSChain/consensus/clique"
"github.com/XinFinOrg/XDPoSChain/core/state" "github.com/XinFinOrg/XDPoSChain/core/state"
"github.com/XinFinOrg/XDPoSChain/core/types" "github.com/XinFinOrg/XDPoSChain/core/types"
@ -34,11 +36,7 @@ import (
) )
func SigHash(header *types.Header) (hash common.Hash) { func SigHash(header *types.Header) (hash common.Hash) {
switch params.BlockConsensusVersion(header.Number) { return utils.SigHash(header)
// TODO: Add switch case for 2.0 later
default: // Default "1.0"
return engine_v1.SigHash(header)
}
} }
// XDPoS is the delegated-proof-of-stake consensus engine proposed to support the // XDPoS is the delegated-proof-of-stake consensus engine proposed to support the
@ -56,6 +54,7 @@ type XDPoS struct {
// The exact consensus engine with different versions // The exact consensus engine with different versions
EngineV1 engine_v1.XDPoS_v1 EngineV1 engine_v1.XDPoS_v1
EngineV2 engine_v2.XDPoS_v2
} }
// New creates a XDPoS delegated-proof-of-stake consensus engine with the initial // New creates a XDPoS delegated-proof-of-stake consensus engine with the initial
@ -72,26 +71,34 @@ func New(config *params.XDPoSConfig, db ethdb.Database) *XDPoS {
return &XDPoS{ return &XDPoS{
config: &conf, config: &conf,
db: db,
signingTxsCache: signingTxsCache, signingTxsCache: signingTxsCache,
EngineV1: *engine_v1.New(&conf, db), EngineV1: *engine_v1.New(&conf, db),
EngineV2: *engine_v2.New(&conf, db),
} }
} }
// NewFullFaker creates an ethash consensus engine with a full fake scheme that // NewFullFaker creates an ethash consensus engine with a full fake scheme that
// accepts all blocks as valid, without checking any consensus rules whatsoever. // accepts all blocks as valid, without checking any consensus rules whatsoever.
func NewFaker(db ethdb.Database) *XDPoS { func NewFaker(db ethdb.Database, chainConfig *params.ChainConfig) *XDPoS {
var fakeEngine *XDPoS var fakeEngine *XDPoS
// Set any missing consensus parameters to their defaults // Set any missing consensus parameters to their defaults
conf := params.TestXDPoSMockChainConfig.XDPoS conf := params.TestXDPoSMockChainConfig.XDPoS
if chainConfig != nil {
conf = chainConfig.XDPoS
}
// Allocate the snapshot caches and create the engine // Allocate the snapshot caches and create the engine
signingTxsCache, _ := lru.New(utils.BlockSignersCacheLimit) signingTxsCache, _ := lru.New(utils.BlockSignersCacheLimit)
fakeEngine = &XDPoS{ fakeEngine = &XDPoS{
config: conf, config: conf,
db: db,
signingTxsCache: signingTxsCache, signingTxsCache: signingTxsCache,
EngineV1: *engine_v1.NewFaker(db), EngineV1: *engine_v1.NewFaker(db, conf),
EngineV2: *engine_v2.NewFaker(db, conf),
} }
return fakeEngine return fakeEngine
} }
@ -101,92 +108,94 @@ func NewFaker(db ethdb.Database) *XDPoS {
*/ */
// APIs implements consensus.Engine, returning the user facing RPC API to allow // APIs implements consensus.Engine, returning the user facing RPC API to allow
// controlling the signer voting. // controlling the signer voting.
func (c *XDPoS) APIs(chain consensus.ChainReader) []rpc.API { func (x *XDPoS) APIs(chain consensus.ChainReader) []rpc.API {
return []rpc.API{{ return []rpc.API{{
Namespace: "XDPoS", Namespace: "XDPoS",
Version: "1.0", Version: "1.0",
Service: &API{chain: chain, XDPoS: c}, Service: &API{chain: chain, XDPoS: x},
Public: true, Public: true,
}} }}
} }
// Author implements consensus.Engine, returning the Ethereum address recovered // Author implements consensus.Engine, returning the Ethereum address recovered
// from the signature in the header's extra-data section. // from the signature in the header's extra-data section.
func (c *XDPoS) Author(header *types.Header) (common.Address, error) { func (x *XDPoS) Author(header *types.Header) (common.Address, error) {
switch params.BlockConsensusVersion(header.Number) { switch x.config.BlockConsensusVersion(header.Number) {
default: // Default "1.0" case params.ConsensusEngineVersion2:
return c.EngineV1.Author(header) return x.EngineV2.Author(header)
default: // Default "v1"
return x.EngineV1.Author(header)
} }
} }
// VerifyHeader checks whether a header conforms to the consensus rules. // VerifyHeader checks whether a header conforms to the consensus rules.
func (c *XDPoS) VerifyHeader(chain consensus.ChainReader, header *types.Header, fullVerify bool) error { func (x *XDPoS) VerifyHeader(chain consensus.ChainReader, header *types.Header, fullVerify bool) error {
switch params.BlockConsensusVersion(header.Number) { switch x.config.BlockConsensusVersion(header.Number) {
default: // Default "1.0" default: // Default "v1"
return c.EngineV1.VerifyHeader(chain, header, fullVerify) return x.EngineV1.VerifyHeader(chain, header, fullVerify)
} }
} }
// VerifyHeaders is similar to VerifyHeader, but verifies a batch of headers. The // VerifyHeaders is similar to VerifyHeader, but verifies a batch of headers. The
// method returns a quit channel to abort the operations and a results channel to // method returns a quit channel to abort the operations and a results channel to
// retrieve the async verifications (the order is that of the input slice). // retrieve the async verifications (the order is that of the input slice).
func (c *XDPoS) VerifyHeaders(chain consensus.ChainReader, headers []*types.Header, fullVerifies []bool) (chan<- struct{}, <-chan error) { func (x *XDPoS) VerifyHeaders(chain consensus.ChainReader, headers []*types.Header, fullVerifies []bool) (chan<- struct{}, <-chan error) {
// TODO: (Hashlab) This funciton is a special case // TODO: (Hashlab) This funciton is a special case
return c.EngineV1.VerifyHeaders(chain, headers, fullVerifies) return x.EngineV1.VerifyHeaders(chain, headers, fullVerifies)
} }
// VerifyUncles implements consensus.Engine, always returning an error for any // VerifyUncles implements consensus.Engine, always returning an error for any
// uncles as this consensus mechanism doesn't permit uncles. // uncles as this consensus mechanism doesn't permit uncles.
func (c *XDPoS) VerifyUncles(chain consensus.ChainReader, block *types.Block) error { func (x *XDPoS) VerifyUncles(chain consensus.ChainReader, block *types.Block) error {
switch params.BlockConsensusVersion(block.Number()) { switch x.config.BlockConsensusVersion(block.Number()) {
default: // Default "1.0" default: // Default "v1"
return c.EngineV1.VerifyUncles(chain, block) return x.EngineV1.VerifyUncles(chain, block)
} }
} }
// VerifySeal implements consensus.Engine, checking whether the signature contained // VerifySeal implements consensus.Engine, checking whether the signature contained
// in the header satisfies the consensus protocol requirements. // in the header satisfies the consensus protocol requirements.
func (c *XDPoS) VerifySeal(chain consensus.ChainReader, header *types.Header) error { func (x *XDPoS) VerifySeal(chain consensus.ChainReader, header *types.Header) error {
switch params.BlockConsensusVersion(header.Number) { switch x.config.BlockConsensusVersion(header.Number) {
default: // Default "1.0" default: // Default "v1"
return c.EngineV1.VerifySeal(chain, header) return x.EngineV1.VerifySeal(chain, header)
} }
} }
// Prepare implements consensus.Engine, preparing all the consensus fields of the // Prepare implements consensus.Engine, preparing all the consensus fields of the
// header for running the transactions on top. // header for running the transactions on top.
func (c *XDPoS) Prepare(chain consensus.ChainReader, header *types.Header) error { func (x *XDPoS) Prepare(chain consensus.ChainReader, header *types.Header) error {
switch params.BlockConsensusVersion(header.Number) { switch x.config.BlockConsensusVersion(header.Number) {
default: // Default "1.0" default: // Default "v1"
return c.EngineV1.Prepare(chain, header) return x.EngineV1.Prepare(chain, header)
} }
} }
// Finalize implements consensus.Engine, ensuring no uncles are set, nor block // Finalize implements consensus.Engine, ensuring no uncles are set, nor block
// rewards given, and returns the final block. // rewards given, and returns the final block.
func (c *XDPoS) Finalize(chain consensus.ChainReader, header *types.Header, state *state.StateDB, parentState *state.StateDB, txs []*types.Transaction, uncles []*types.Header, receipts []*types.Receipt) (*types.Block, error) { func (x *XDPoS) Finalize(chain consensus.ChainReader, header *types.Header, state *state.StateDB, parentState *state.StateDB, txs []*types.Transaction, uncles []*types.Header, receipts []*types.Receipt) (*types.Block, error) {
switch params.BlockConsensusVersion(header.Number) { switch x.config.BlockConsensusVersion(header.Number) {
default: // Default "1.0" default: // Default "v1"
return c.EngineV1.Finalize(chain, header, state, parentState, txs, uncles, receipts) return x.EngineV1.Finalize(chain, header, state, parentState, txs, uncles, receipts)
} }
} }
// Seal implements consensus.Engine, attempting to create a sealed block using // Seal implements consensus.Engine, attempting to create a sealed block using
// the local signing credentials. // the local signing credentials.
func (c *XDPoS) Seal(chain consensus.ChainReader, block *types.Block, stop <-chan struct{}) (*types.Block, error) { func (x *XDPoS) Seal(chain consensus.ChainReader, block *types.Block, stop <-chan struct{}) (*types.Block, error) {
switch params.BlockConsensusVersion(block.Number()) { switch x.config.BlockConsensusVersion(block.Number()) {
default: // Default "1.0" default: // Default "v1"
return c.EngineV1.Seal(chain, block, stop) return x.EngineV1.Seal(chain, block, stop)
} }
} }
// CalcDifficulty is the difficulty adjustment algorithm. It returns the difficulty // CalcDifficulty is the difficulty adjustment algorithm. It returns the difficulty
// that a new block should have based on the previous blocks in the chain and the // that a new block should have based on the previous blocks in the chain and the
// current signer. // current signer.
func (c *XDPoS) CalcDifficulty(chain consensus.ChainReader, time uint64, parent *types.Header) *big.Int { func (x *XDPoS) CalcDifficulty(chain consensus.ChainReader, time uint64, parent *types.Header) *big.Int {
switch params.BlockConsensusVersion(parent.Number) { switch x.config.BlockConsensusVersion(parent.Number) {
default: // Default "1.0" default: // Default "v1"
return c.EngineV1.CalcDifficulty(chain, time, parent) return x.EngineV1.CalcDifficulty(chain, time, parent)
} }
} }
@ -196,81 +205,81 @@ func (c *XDPoS) CalcDifficulty(chain consensus.ChainReader, time uint64, parent
// Authorize injects a private key into the consensus engine to mint new blocks // Authorize injects a private key into the consensus engine to mint new blocks
// with. // with.
func (c *XDPoS) Authorize(signer common.Address, signFn clique.SignerFn) { func (x *XDPoS) Authorize(signer common.Address, signFn clique.SignerFn) {
// Authorize each consensus individually // Authorize each consensus individually
c.EngineV1.Authorize(signer, signFn) x.EngineV1.Authorize(signer, signFn)
} }
func (c *XDPoS) GetPeriod() uint64 { func (x *XDPoS) GetPeriod() uint64 {
return c.config.Period return x.config.Period
} }
func (c *XDPoS) IsAuthorisedAddress(header *types.Header, chain consensus.ChainReader, address common.Address) bool { func (x *XDPoS) IsAuthorisedAddress(header *types.Header, chain consensus.ChainReader, address common.Address) bool {
switch params.BlockConsensusVersion(header.Number) { switch x.config.BlockConsensusVersion(header.Number) {
default: // Default "1.0" default: // Default "v1"
return c.EngineV1.IsAuthorisedAddress(header, chain, address) return x.EngineV1.IsAuthorisedAddress(header, chain, address)
} }
} }
func (c *XDPoS) GetMasternodes(chain consensus.ChainReader, header *types.Header) []common.Address { func (x *XDPoS) GetMasternodes(chain consensus.ChainReader, header *types.Header) []common.Address {
switch params.BlockConsensusVersion(header.Number) { switch x.config.BlockConsensusVersion(header.Number) {
default: // Default "1.0" default: // Default "v1"
return c.EngineV1.GetMasternodes(chain, header) return x.EngineV1.GetMasternodes(chain, header)
} }
} }
func (c *XDPoS) YourTurn(chain consensus.ChainReader, parent *types.Header, signer common.Address) (int, int, int, bool, error) { func (x *XDPoS) YourTurn(chain consensus.ChainReader, parent *types.Header, signer common.Address) (int, int, int, bool, error) {
switch params.BlockConsensusVersion(parent.Number) { switch x.config.BlockConsensusVersion(parent.Number) {
default: // Default "1.0" default: // Default "v1"
return c.EngineV1.YourTurn(chain, parent, signer) return x.EngineV1.YourTurn(chain, parent, signer)
} }
} }
func (c *XDPoS) GetValidator(creator common.Address, chain consensus.ChainReader, header *types.Header) (common.Address, error) { func (x *XDPoS) GetValidator(creator common.Address, chain consensus.ChainReader, header *types.Header) (common.Address, error) {
switch params.BlockConsensusVersion(header.Number) { switch x.config.BlockConsensusVersion(header.Number) {
default: // Default "1.0" default: // Default "v1"
return c.EngineV1.GetValidator(creator, chain, header) return x.EngineV1.GetValidator(creator, chain, header)
} }
} }
func (c *XDPoS) UpdateMasternodes(chain consensus.ChainReader, header *types.Header, ms []utils.Masternode) error { func (x *XDPoS) UpdateMasternodes(chain consensus.ChainReader, header *types.Header, ms []utils.Masternode) error {
switch params.BlockConsensusVersion(header.Number) { switch x.config.BlockConsensusVersion(header.Number) {
default: // Default "1.0" default: // Default "v1"
return c.EngineV1.UpdateMasternodes(chain, header, ms) return x.EngineV1.UpdateMasternodes(chain, header, ms)
} }
} }
func (c *XDPoS) RecoverSigner(header *types.Header) (common.Address, error) { func (x *XDPoS) RecoverSigner(header *types.Header) (common.Address, error) {
switch params.BlockConsensusVersion(header.Number) { switch x.config.BlockConsensusVersion(header.Number) {
default: // Default "1.0" default: // Default "v1"
return c.EngineV1.RecoverSigner(header) return x.EngineV1.RecoverSigner(header)
} }
} }
func (c *XDPoS) RecoverValidator(header *types.Header) (common.Address, error) { func (x *XDPoS) RecoverValidator(header *types.Header) (common.Address, error) {
switch params.BlockConsensusVersion(header.Number) { switch x.config.BlockConsensusVersion(header.Number) {
default: // Default "1.0" default: // Default "v1"
return c.EngineV1.RecoverValidator(header) return x.EngineV1.RecoverValidator(header)
} }
} }
// Get master nodes over extra data of previous checkpoint block. // Get master nodes over extra data of previous checkpoint block.
func (c *XDPoS) GetMasternodesFromCheckpointHeader(preCheckpointHeader *types.Header, n, e uint64) []common.Address { func (x *XDPoS) GetMasternodesFromCheckpointHeader(preCheckpointHeader *types.Header, n, e uint64) []common.Address {
switch params.BlockConsensusVersion(preCheckpointHeader.Number) { switch x.config.BlockConsensusVersion(preCheckpointHeader.Number) {
default: // Default "1.0" default: // Default "v1"
return c.EngineV1.GetMasternodesFromCheckpointHeader(preCheckpointHeader, n, e) return x.EngineV1.GetMasternodesFromCheckpointHeader(preCheckpointHeader, n, e)
} }
} }
// Same DB across all consensus engines // Same DB across all consensus engines
func (c *XDPoS) GetDb() ethdb.Database { func (x *XDPoS) GetDb() ethdb.Database {
return c.db return x.db
} }
func (c *XDPoS) GetSnapshot(chain consensus.ChainReader, header *types.Header) (*utils.PublicApiSnapshot, error) { func (x *XDPoS) GetSnapshot(chain consensus.ChainReader, header *types.Header) (*utils.PublicApiSnapshot, error) {
switch params.BlockConsensusVersion(header.Number) { switch x.config.BlockConsensusVersion(header.Number) {
default: // Default "1.0" default: // Default "v1"
sp, err := c.EngineV1.GetSnapshot(chain, header) sp, err := x.EngineV1.GetSnapshot(chain, header)
// Convert to a standard PublicApiSnapshot type, otherwise it's a breaking change to API // Convert to a standard PublicApiSnapshot type, otherwise it's a breaking change to API
return &utils.PublicApiSnapshot{ return &utils.PublicApiSnapshot{
Number: sp.Number, Number: sp.Number,
@ -283,10 +292,10 @@ func (c *XDPoS) GetSnapshot(chain consensus.ChainReader, header *types.Header) (
} }
} }
func (c *XDPoS) GetAuthorisedSignersFromSnapshot(chain consensus.ChainReader, header *types.Header) ([]common.Address, error) { func (x *XDPoS) GetAuthorisedSignersFromSnapshot(chain consensus.ChainReader, header *types.Header) ([]common.Address, error) {
switch params.BlockConsensusVersion(header.Number) { switch x.config.BlockConsensusVersion(header.Number) {
default: // Default "1.0" default: // Default "v1"
return c.EngineV1.GetAuthorisedSignersFromSnapshot(chain, header) return x.EngineV1.GetAuthorisedSignersFromSnapshot(chain, header)
} }
} }
@ -295,7 +304,7 @@ Caching
*/ */
// Cache signing transaction data into BlockSingers cache object // Cache signing transaction data into BlockSingers cache object
func (c *XDPoS) CacheNoneTIPSigningTxs(header *types.Header, txs []*types.Transaction, receipts []*types.Receipt) []*types.Transaction { func (x *XDPoS) CacheNoneTIPSigningTxs(header *types.Header, txs []*types.Transaction, receipts []*types.Receipt) []*types.Transaction {
signTxs := []*types.Transaction{} signTxs := []*types.Transaction{}
for _, tx := range txs { for _, tx := range txs {
if tx.IsSigningTransaction() { if tx.IsSigningTransaction() {
@ -320,13 +329,13 @@ func (c *XDPoS) CacheNoneTIPSigningTxs(header *types.Header, txs []*types.Transa
} }
log.Debug("Save tx signers to cache", "hash", header.Hash().String(), "number", header.Number, "len(txs)", len(signTxs)) log.Debug("Save tx signers to cache", "hash", header.Hash().String(), "number", header.Number, "len(txs)", len(signTxs))
c.signingTxsCache.Add(header.Hash(), signTxs) x.signingTxsCache.Add(header.Hash(), signTxs)
return signTxs return signTxs
} }
// Cache // Cache
func (c *XDPoS) CacheSigningTxs(hash common.Hash, txs []*types.Transaction) []*types.Transaction { func (x *XDPoS) CacheSigningTxs(hash common.Hash, txs []*types.Transaction) []*types.Transaction {
signTxs := []*types.Transaction{} signTxs := []*types.Transaction{}
for _, tx := range txs { for _, tx := range txs {
if tx.IsSigningTransaction() { if tx.IsSigningTransaction() {
@ -334,10 +343,10 @@ func (c *XDPoS) CacheSigningTxs(hash common.Hash, txs []*types.Transaction) []*t
} }
} }
log.Debug("Save tx signers to cache", "hash", hash.String(), "len(txs)", len(signTxs)) log.Debug("Save tx signers to cache", "hash", hash.String(), "len(txs)", len(signTxs))
c.signingTxsCache.Add(hash, signTxs) x.signingTxsCache.Add(hash, signTxs)
return signTxs return signTxs
} }
func (c *XDPoS) GetCachedSigningTxs(hash common.Hash) (interface{}, bool) { func (x *XDPoS) GetCachedSigningTxs(hash common.Hash) (interface{}, bool) {
return c.signingTxsCache.Get(hash) return x.signingTxsCache.Get(hash)
} }

View file

@ -1,7 +1,18 @@
package XDPoS package XDPoS
import "testing" import (
"testing"
func TestNewAdaptorShallContainMultipleConsensusEngine(t *testing.T) { "github.com/XinFinOrg/XDPoSChain/core/rawdb"
"github.com/XinFinOrg/XDPoSChain/params"
"github.com/stretchr/testify/assert"
)
func TestAdaptorShouldShareDbWithV1Engine(t *testing.T) {
database := rawdb.NewMemoryDatabase()
config := params.TestXDPoSMockChainConfig.XDPoS
engine := New(config, database)
assert := assert.New(t)
assert.Equal(engine.EngineV1.GetDb(), engine.GetDb())
} }

View file

@ -15,62 +15,19 @@ import (
"github.com/XinFinOrg/XDPoSChain/accounts" "github.com/XinFinOrg/XDPoSChain/accounts"
"github.com/XinFinOrg/XDPoSChain/common" "github.com/XinFinOrg/XDPoSChain/common"
"github.com/XinFinOrg/XDPoSChain/consensus" "github.com/XinFinOrg/XDPoSChain/consensus"
"github.com/XinFinOrg/XDPoSChain/consensus/XDPoS/utils" "github.com/XinFinOrg/XDPoSChain/consensus/XDPoS/utils"
"github.com/XinFinOrg/XDPoSChain/consensus/clique" "github.com/XinFinOrg/XDPoSChain/consensus/clique"
"github.com/XinFinOrg/XDPoSChain/consensus/misc" "github.com/XinFinOrg/XDPoSChain/consensus/misc"
"github.com/XinFinOrg/XDPoSChain/core/state" "github.com/XinFinOrg/XDPoSChain/core/state"
"github.com/XinFinOrg/XDPoSChain/core/types" "github.com/XinFinOrg/XDPoSChain/core/types"
"github.com/XinFinOrg/XDPoSChain/crypto" "github.com/XinFinOrg/XDPoSChain/crypto"
"github.com/XinFinOrg/XDPoSChain/crypto/sha3"
"github.com/XinFinOrg/XDPoSChain/ethdb" "github.com/XinFinOrg/XDPoSChain/ethdb"
"github.com/XinFinOrg/XDPoSChain/log" "github.com/XinFinOrg/XDPoSChain/log"
"github.com/XinFinOrg/XDPoSChain/params" "github.com/XinFinOrg/XDPoSChain/params"
"github.com/XinFinOrg/XDPoSChain/rlp"
lru "github.com/hashicorp/golang-lru" lru "github.com/hashicorp/golang-lru"
) )
// SignerFn is a signer callback function to request a hash to be signed by a
// backing account.
//type SignerFn func(accounts.Account, []byte) ([]byte, error)
// sigHash returns the hash which is used as input for the delegated-proof-of-stake
// signing. It is the hash of the entire header apart from the 65 byte signature
// contained at the end of the extra data.
//
// Note, the method requires the extra data to be at least 65 bytes, otherwise it
// panics. This is done to avoid accidentally using both forms (signature present
// or not), which could be abused to produce different hashes for the same header.
func sigHash(header *types.Header) (hash common.Hash) {
hasher := sha3.NewKeccak256()
err := rlp.Encode(hasher, []interface{}{
header.ParentHash,
header.UncleHash,
header.Coinbase,
header.Root,
header.TxHash,
header.ReceiptHash,
header.Bloom,
header.Difficulty,
header.Number,
header.GasLimit,
header.GasUsed,
header.Time,
header.Extra[:len(header.Extra)-65], // Yes, this will panic if extra is too short
header.MixDigest,
header.Nonce,
})
if err != nil {
log.Debug("Fail to encode", err)
}
hasher.Sum(hash[:0])
return hash
}
func SigHash(header *types.Header) (hash common.Hash) {
return sigHash(header)
}
// ecrecover extracts the Ethereum account address from a signed header. // ecrecover extracts the Ethereum account address from a signed header.
func ecrecover(header *types.Header, sigcache *lru.ARCCache) (common.Address, error) { func ecrecover(header *types.Header, sigcache *lru.ARCCache) (common.Address, error) {
// If the signature's already cached, return that // If the signature's already cached, return that
@ -85,7 +42,7 @@ func ecrecover(header *types.Header, sigcache *lru.ARCCache) (common.Address, er
signature := header.Extra[len(header.Extra)-utils.ExtraSeal:] signature := header.Extra[len(header.Extra)-utils.ExtraSeal:]
// Recover the public key and the Ethereum address // Recover the public key and the Ethereum address
pubkey, err := crypto.Ecrecover(sigHash(header).Bytes(), signature) pubkey, err := crypto.Ecrecover(utils.SigHash(header).Bytes(), signature)
if err != nil { if err != nil {
return common.Address{}, err return common.Address{}, err
} }
@ -148,25 +105,25 @@ func New(config *params.XDPoSConfig, db ethdb.Database) *XDPoS_v1 {
// Author implements consensus.Engine, returning the Ethereum address recovered // Author implements consensus.Engine, returning the Ethereum address recovered
// from the signature in the header's extra-data section. // from the signature in the header's extra-data section.
func (c *XDPoS_v1) Author(header *types.Header) (common.Address, error) { func (x *XDPoS_v1) Author(header *types.Header) (common.Address, error) {
return ecrecover(header, c.signatures) return ecrecover(header, x.signatures)
} }
// VerifyHeader checks whether a header conforms to the consensus rules. // VerifyHeader checks whether a header conforms to the consensus rules.
func (c *XDPoS_v1) VerifyHeader(chain consensus.ChainReader, header *types.Header, fullVerify bool) error { func (x *XDPoS_v1) VerifyHeader(chain consensus.ChainReader, header *types.Header, fullVerify bool) error {
return c.verifyHeaderWithCache(chain, header, nil, fullVerify) return x.verifyHeaderWithCache(chain, header, nil, fullVerify)
} }
// VerifyHeaders is similar to VerifyHeader, but verifies a batch of headers. The // VerifyHeaders is similar to VerifyHeader, but verifies a batch of headers. The
// method returns a quit channel to abort the operations and a results channel to // method returns a quit channel to abort the operations and a results channel to
// retrieve the async verifications (the order is that of the input slice). // retrieve the async verifications (the order is that of the input slice).
func (c *XDPoS_v1) VerifyHeaders(chain consensus.ChainReader, headers []*types.Header, fullVerifies []bool) (chan<- struct{}, <-chan error) { func (x *XDPoS_v1) VerifyHeaders(chain consensus.ChainReader, headers []*types.Header, fullVerifies []bool) (chan<- struct{}, <-chan error) {
abort := make(chan struct{}) abort := make(chan struct{})
results := make(chan error, len(headers)) results := make(chan error, len(headers))
go func() { go func() {
for i, header := range headers { for i, header := range headers {
err := c.verifyHeaderWithCache(chain, header, headers[:i], fullVerifies[i]) err := x.verifyHeaderWithCache(chain, header, headers[:i], fullVerifies[i])
select { select {
case <-abort: case <-abort:
@ -178,14 +135,14 @@ func (c *XDPoS_v1) VerifyHeaders(chain consensus.ChainReader, headers []*types.H
return abort, results return abort, results
} }
func (c *XDPoS_v1) verifyHeaderWithCache(chain consensus.ChainReader, header *types.Header, parents []*types.Header, fullVerify bool) error { func (x *XDPoS_v1) verifyHeaderWithCache(chain consensus.ChainReader, header *types.Header, parents []*types.Header, fullVerify bool) error {
_, check := c.verifiedHeaders.Get(header.Hash()) _, check := x.verifiedHeaders.Get(header.Hash())
if check { if check {
return nil return nil
} }
err := c.verifyHeader(chain, header, parents, fullVerify) err := x.verifyHeader(chain, header, parents, fullVerify)
if err == nil { if err == nil {
c.verifiedHeaders.Add(header.Hash(), true) x.verifiedHeaders.Add(header.Hash(), true)
} }
return err return err
} }
@ -194,9 +151,9 @@ func (c *XDPoS_v1) verifyHeaderWithCache(chain consensus.ChainReader, header *ty
// caller may optionally pass in a batch of parents (ascending order) to avoid // caller may optionally pass in a batch of parents (ascending order) to avoid
// looking those up from the database. This is useful for concurrently verifying // looking those up from the database. This is useful for concurrently verifying
// a batch of new headers. // a batch of new headers.
func (c *XDPoS_v1) verifyHeader(chain consensus.ChainReader, header *types.Header, parents []*types.Header, fullVerify bool) error { func (x *XDPoS_v1) 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 we're running a engine faking, accept any block as valid
if c.config.SkipValidation { if x.config.SkipValidation {
return nil return nil
} }
if common.IsTestnet { if common.IsTestnet {
@ -207,7 +164,7 @@ func (c *XDPoS_v1) verifyHeader(chain consensus.ChainReader, header *types.Heade
} }
number := header.Number.Uint64() number := header.Number.Uint64()
if fullVerify { if fullVerify {
if header.Number.Uint64() > c.config.Epoch && len(header.Validator) == 0 { if header.Number.Uint64() > x.config.Epoch && len(header.Validator) == 0 {
return consensus.ErrNoValidatorSignature return consensus.ErrNoValidatorSignature
} }
// Don't waste time checking blocks from the future // Don't waste time checking blocks from the future
@ -216,7 +173,7 @@ func (c *XDPoS_v1) verifyHeader(chain consensus.ChainReader, header *types.Heade
} }
} }
// Checkpoint blocks need to enforce zero beneficiary // Checkpoint blocks need to enforce zero beneficiary
checkpoint := (number % c.config.Epoch) == 0 checkpoint := (number % x.config.Epoch) == 0
if checkpoint && header.Coinbase != (common.Address{}) { if checkpoint && header.Coinbase != (common.Address{}) {
return utils.ErrInvalidCheckpointBeneficiary return utils.ErrInvalidCheckpointBeneficiary
} }
@ -256,14 +213,14 @@ func (c *XDPoS_v1) verifyHeader(chain consensus.ChainReader, header *types.Heade
return err return err
} }
// All basic checks passed, verify cascading fields // All basic checks passed, verify cascading fields
return c.verifyCascadingFields(chain, header, parents, fullVerify) return x.verifyCascadingFields(chain, header, parents, fullVerify)
} }
// verifyCascadingFields verifies all the header fields that are not standalone, // verifyCascadingFields verifies all the header fields that are not standalone,
// rather depend on a batch of previous headers. The caller may optionally pass // rather depend on a batch of previous headers. The caller may optionally pass
// in a batch of parents (ascending order) to avoid looking those up from the // in a batch of parents (ascending order) to avoid looking those up from the
// database. This is useful for concurrently verifying a batch of new headers. // database. This is useful for concurrently verifying a batch of new headers.
func (c *XDPoS_v1) verifyCascadingFields(chain consensus.ChainReader, header *types.Header, parents []*types.Header, fullVerify bool) error { func (x *XDPoS_v1) verifyCascadingFields(chain consensus.ChainReader, header *types.Header, parents []*types.Header, fullVerify bool) error {
// The genesis block is the always valid dead-end // The genesis block is the always valid dead-end
number := header.Number.Uint64() number := header.Number.Uint64()
if number == 0 { if number == 0 {
@ -279,12 +236,12 @@ func (c *XDPoS_v1) verifyCascadingFields(chain consensus.ChainReader, header *ty
if parent == nil || parent.Number.Uint64() != number-1 || parent.Hash() != header.ParentHash { if parent == nil || parent.Number.Uint64() != number-1 || parent.Hash() != header.ParentHash {
return consensus.ErrUnknownAncestor return consensus.ErrUnknownAncestor
} }
if parent.Time.Uint64()+c.config.Period > header.Time.Uint64() { if parent.Time.Uint64()+x.config.Period > header.Time.Uint64() {
return utils.ErrInvalidTimestamp return utils.ErrInvalidTimestamp
} }
if number%c.config.Epoch != 0 { if number%x.config.Epoch != 0 {
return c.verifySeal(chain, header, parents, fullVerify) return x.verifySeal(chain, header, parents, fullVerify)
} }
/* /*
@ -292,42 +249,42 @@ func (c *XDPoS_v1) verifyCascadingFields(chain consensus.ChainReader, header *ty
when it happens we get the signers list by requesting smart contract when it happens we get the signers list by requesting smart contract
*/ */
// Retrieve the snapshot needed to verify this header and cache it // Retrieve the snapshot needed to verify this header and cache it
snap, err := c.snapshot(chain, number-1, header.ParentHash, parents) snap, err := x.snapshot(chain, number-1, header.ParentHash, parents)
if err != nil { if err != nil {
return err return err
} }
signers := snap.GetSigners() signers := snap.GetSigners()
err = c.checkSignersOnCheckpoint(chain, header, signers) err = x.checkSignersOnCheckpoint(chain, header, signers)
if err == nil { if err == nil {
return c.verifySeal(chain, header, parents, fullVerify) return x.verifySeal(chain, header, parents, fullVerify)
} }
signers, err = c.getSignersFromContract(chain, header) signers, err = x.getSignersFromContract(chain, header)
if err != nil { if err != nil {
return err return err
} }
err = c.checkSignersOnCheckpoint(chain, header, signers) err = x.checkSignersOnCheckpoint(chain, header, signers)
if err == nil { if err == nil {
return c.verifySeal(chain, header, parents, fullVerify) return x.verifySeal(chain, header, parents, fullVerify)
} }
return err return err
} }
func (c *XDPoS_v1) checkSignersOnCheckpoint(chain consensus.ChainReader, header *types.Header, signers []common.Address) error { func (x *XDPoS_v1) checkSignersOnCheckpoint(chain consensus.ChainReader, header *types.Header, signers []common.Address) error {
number := header.Number.Uint64() number := header.Number.Uint64()
// ignore signerCheck at checkpoint block 14458500 due to wrong snapshot at gap 14458495 // ignore signerCheck at checkpoint block 14458500 due to wrong snapshot at gap 14458495
if number == common.IgnoreSignerCheckBlock { if number == common.IgnoreSignerCheckBlock {
return nil return nil
} }
penPenalties := []common.Address{} penPenalties := []common.Address{}
if c.HookPenalty != nil || c.HookPenaltyTIPSigning != nil { if x.HookPenalty != nil || x.HookPenaltyTIPSigning != nil {
var err error var err error
if chain.Config().IsTIPSigning(header.Number) { if chain.Config().IsTIPSigning(header.Number) {
penPenalties, err = c.HookPenaltyTIPSigning(chain, header, signers) penPenalties, err = x.HookPenaltyTIPSigning(chain, header, signers)
} else { } else {
penPenalties, err = c.HookPenalty(chain, number) penPenalties, err = x.HookPenalty(chain, number)
} }
if err != nil { if err != nil {
return err return err
@ -342,8 +299,8 @@ func (c *XDPoS_v1) checkSignersOnCheckpoint(chain consensus.ChainReader, header
} }
signers = common.RemoveItemFromArray(signers, penPenalties) signers = common.RemoveItemFromArray(signers, penPenalties)
for i := 1; i <= common.LimitPenaltyEpoch; i++ { for i := 1; i <= common.LimitPenaltyEpoch; i++ {
if number > uint64(i)*c.config.Epoch { if number > uint64(i)*x.config.Epoch {
signers = removePenaltiesFromBlock(chain, signers, number-uint64(i)*c.config.Epoch) signers = removePenaltiesFromBlock(chain, signers, number-uint64(i)*x.config.Epoch)
} }
} }
extraSuffix := len(header.Extra) - utils.ExtraSeal extraSuffix := len(header.Extra) - utils.ExtraSeal
@ -354,8 +311,8 @@ func (c *XDPoS_v1) checkSignersOnCheckpoint(chain consensus.ChainReader, header
log.Error("Masternodes lists are different in checkpoint header and snapshot", "number", number, "masternodes_from_checkpoint_header", masternodesFromCheckpointHeader, "masternodes_in_snapshot", signers, "penList", penPenalties) log.Error("Masternodes lists are different in checkpoint header and snapshot", "number", number, "masternodes_from_checkpoint_header", masternodesFromCheckpointHeader, "masternodes_in_snapshot", signers, "penList", penPenalties)
return utils.ErrInvalidCheckpointSigners return utils.ErrInvalidCheckpointSigners
} }
if c.HookVerifyMNs != nil { if x.HookVerifyMNs != nil {
err := c.HookVerifyMNs(header, signers) err := x.HookVerifyMNs(header, signers)
if err != nil { if err != nil {
return err return err
} }
@ -364,8 +321,8 @@ func (c *XDPoS_v1) checkSignersOnCheckpoint(chain consensus.ChainReader, header
return nil return nil
} }
func (c *XDPoS_v1) IsAuthorisedAddress(header *types.Header, chain consensus.ChainReader, address common.Address) bool { func (x *XDPoS_v1) IsAuthorisedAddress(header *types.Header, chain consensus.ChainReader, address common.Address) bool {
snap, err := c.GetSnapshot(chain, header) snap, err := x.GetSnapshot(chain, header)
if err != nil { if err != nil {
log.Error("[IsAuthorisedAddress] Can't get snapshot with at ", "number", header.Number, "hash", header.Hash().Hex(), "err", err) log.Error("[IsAuthorisedAddress] Can't get snapshot with at ", "number", header.Number, "hash", header.Hash().Hex(), "err", err)
return false return false
@ -376,26 +333,26 @@ func (c *XDPoS_v1) IsAuthorisedAddress(header *types.Header, chain consensus.Cha
return false return false
} }
func (c *XDPoS_v1) GetSnapshot(chain consensus.ChainReader, header *types.Header) (*SnapshotV1, error) { func (x *XDPoS_v1) GetSnapshot(chain consensus.ChainReader, header *types.Header) (*SnapshotV1, error) {
number := header.Number.Uint64() number := header.Number.Uint64()
log.Trace("get snapshot", "number", number, "hash", header.Hash()) log.Trace("get snapshot", "number", number, "hash", header.Hash())
snap, err := c.snapshot(chain, number, header.Hash(), nil) snap, err := x.snapshot(chain, number, header.Hash(), nil)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return snap, nil return snap, nil
} }
func (c *XDPoS_v1) GetAuthorisedSignersFromSnapshot(chain consensus.ChainReader, header *types.Header) ([]common.Address, error) { func (x *XDPoS_v1) GetAuthorisedSignersFromSnapshot(chain consensus.ChainReader, header *types.Header) ([]common.Address, error) {
snap, err := c.GetSnapshot(chain, header) snap, err := x.GetSnapshot(chain, header)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return snap.GetSigners(), nil return snap.GetSigners(), nil
} }
func (c *XDPoS_v1) StoreSnapshot(snap *SnapshotV1) error { func (x *XDPoS_v1) StoreSnapshot(snap *SnapshotV1) error {
return snap.store(c.db) return snap.store(x.db)
} }
func position(list []common.Address, x common.Address) int { func position(list []common.Address, x common.Address) int {
@ -407,21 +364,21 @@ func position(list []common.Address, x common.Address) int {
return -1 return -1
} }
func (c *XDPoS_v1) GetMasternodes(chain consensus.ChainReader, header *types.Header) []common.Address { func (x *XDPoS_v1) GetMasternodes(chain consensus.ChainReader, header *types.Header) []common.Address {
n := header.Number.Uint64() n := header.Number.Uint64()
e := c.config.Epoch e := x.config.Epoch
switch { switch {
case n%e == 0: case n%e == 0:
return c.GetMasternodesFromCheckpointHeader(header, n, e) return x.GetMasternodesFromCheckpointHeader(header, n, e)
case n%e != 0: case n%e != 0:
h := chain.GetHeaderByNumber(n - (n % e)) h := chain.GetHeaderByNumber(n - (n % e))
return c.GetMasternodesFromCheckpointHeader(h, n, e) return x.GetMasternodesFromCheckpointHeader(h, n, e)
default: default:
return []common.Address{} return []common.Address{}
} }
} }
func (c *XDPoS_v1) GetPeriod() uint64 { return c.config.Period } func (x *XDPoS_v1) GetPeriod() uint64 { return x.config.Period }
func whoIsCreator(snap *SnapshotV1, header *types.Header) (common.Address, error) { func whoIsCreator(snap *SnapshotV1, header *types.Header) (common.Address, error) {
if header.Number.Uint64() == 0 { if header.Number.Uint64() == 0 {
@ -434,8 +391,8 @@ func whoIsCreator(snap *SnapshotV1, header *types.Header) (common.Address, error
return m, nil return m, nil
} }
func (c *XDPoS_v1) YourTurn(chain consensus.ChainReader, parent *types.Header, signer common.Address) (int, int, int, bool, error) { func (x *XDPoS_v1) YourTurn(chain consensus.ChainReader, parent *types.Header, signer common.Address) (int, int, int, bool, error) {
masternodes := c.GetMasternodes(chain, parent) masternodes := x.GetMasternodes(chain, parent)
// if common.IsTestnet { // if common.IsTestnet {
// // Only three mns hard code for XDC testnet. // // Only three mns hard code for XDC testnet.
@ -446,7 +403,7 @@ func (c *XDPoS_v1) YourTurn(chain consensus.ChainReader, parent *types.Header, s
// } // }
// } // }
snap, err := c.GetSnapshot(chain, parent) snap, err := x.GetSnapshot(chain, parent)
if err != nil { if err != nil {
log.Warn("Failed when trying to commit new work", "err", err) log.Warn("Failed when trying to commit new work", "err", err)
return 0, -1, -1, false, err return 0, -1, -1, false, err
@ -465,7 +422,7 @@ func (c *XDPoS_v1) YourTurn(chain consensus.ChainReader, parent *types.Header, s
preIndex = position(masternodes, pre) preIndex = position(masternodes, pre)
} }
curIndex := position(masternodes, signer) curIndex := position(masternodes, signer)
if signer == c.signer { if signer == x.signer {
log.Debug("Masternodes cycle info", "number of masternodes", len(masternodes), "previous", pre, "position", preIndex, "current", signer, "position", curIndex) log.Debug("Masternodes cycle info", "number of masternodes", len(masternodes), "previous", pre, "position", preIndex, "current", signer, "position", curIndex)
} }
for i, s := range masternodes { for i, s := range masternodes {
@ -478,7 +435,7 @@ func (c *XDPoS_v1) YourTurn(chain consensus.ChainReader, parent *types.Header, s
} }
// snapshot retrieves the authorization snapshot at a given point in time. // snapshot retrieves the authorization snapshot at a given point in time.
func (c *XDPoS_v1) snapshot(chain consensus.ChainReader, number uint64, hash common.Hash, parents []*types.Header) (*SnapshotV1, error) { func (x *XDPoS_v1) snapshot(chain consensus.ChainReader, number uint64, hash common.Hash, parents []*types.Header) (*SnapshotV1, error) {
// Search for a SnapshotV1 in memory or on disk for checkpoints // Search for a SnapshotV1 in memory or on disk for checkpoints
var ( var (
headers []*types.Header headers []*types.Header
@ -486,14 +443,14 @@ func (c *XDPoS_v1) snapshot(chain consensus.ChainReader, number uint64, hash com
) )
for snap == nil { for snap == nil {
// If an in-memory SnapshotV1 was found, use that // If an in-memory SnapshotV1 was found, use that
if s, ok := c.recents.Get(hash); ok { if s, ok := x.recents.Get(hash); ok {
snap = s.(*SnapshotV1) snap = s.(*SnapshotV1)
break break
} }
// If an on-disk checkpoint snapshot can be found, use that // If an on-disk checkpoint snapshot can be found, use that
// checkpoint snapshot = checkpoint - gap // checkpoint snapshot = checkpoint - gap
if (number+c.config.Gap)%c.config.Epoch == 0 { if (number+x.config.Gap)%x.config.Epoch == 0 {
if s, err := loadSnapshot(c.config, c.signatures, c.db, hash); err == nil { if s, err := loadSnapshot(x.config, x.signatures, x.db, hash); err == nil {
log.Trace("Loaded voting snapshot form disk", "number", number, "hash", hash) log.Trace("Loaded voting snapshot form disk", "number", number, "hash", hash)
snap = s snap = s
break break
@ -502,15 +459,15 @@ func (c *XDPoS_v1) snapshot(chain consensus.ChainReader, number uint64, hash com
// If we're at block zero, make a snapshot // If we're at block zero, make a snapshot
if number == 0 { if number == 0 {
genesis := chain.GetHeaderByNumber(0) genesis := chain.GetHeaderByNumber(0)
if err := c.VerifyHeader(chain, genesis, true); err != nil { if err := x.VerifyHeader(chain, genesis, true); err != nil {
return nil, err return nil, err
} }
signers := make([]common.Address, (len(genesis.Extra)-utils.ExtraVanity-utils.ExtraSeal)/common.AddressLength) signers := make([]common.Address, (len(genesis.Extra)-utils.ExtraVanity-utils.ExtraSeal)/common.AddressLength)
for i := 0; i < len(signers); i++ { for i := 0; i < len(signers); i++ {
copy(signers[i][:], genesis.Extra[utils.ExtraVanity+i*common.AddressLength:]) copy(signers[i][:], genesis.Extra[utils.ExtraVanity+i*common.AddressLength:])
} }
snap = newSnapshot(c.config, c.signatures, 0, genesis.Hash(), signers) snap = newSnapshot(x.config, x.signatures, 0, genesis.Hash(), signers)
if err := snap.store(c.db); err != nil { if err := snap.store(x.db); err != nil {
return nil, err return nil, err
} }
log.Trace("Stored genesis voting snapshot to disk") log.Trace("Stored genesis voting snapshot to disk")
@ -543,11 +500,11 @@ func (c *XDPoS_v1) snapshot(chain consensus.ChainReader, number uint64, hash com
if err != nil { if err != nil {
return nil, err return nil, err
} }
c.recents.Add(snap.Hash, snap) x.recents.Add(snap.Hash, snap)
// If we've generated a new checkpoint snapshot, save to disk // If we've generated a new checkpoint snapshot, save to disk
if (snap.Number+c.config.Gap)%c.config.Epoch == 0 { if (snap.Number+x.config.Gap)%x.config.Epoch == 0 {
if err = snap.store(c.db); err != nil { if err = snap.store(x.db); err != nil {
return nil, err return nil, err
} }
log.Trace("Stored voting snapshot to disk", "number", snap.Number, "hash", snap.Hash) log.Trace("Stored voting snapshot to disk", "number", snap.Number, "hash", snap.Hash)
@ -557,7 +514,7 @@ func (c *XDPoS_v1) snapshot(chain consensus.ChainReader, number uint64, hash com
// VerifyUncles implements consensus.Engine, always returning an error for any // VerifyUncles implements consensus.Engine, always returning an error for any
// uncles as this consensus mechanism doesn't permit uncles. // uncles as this consensus mechanism doesn't permit uncles.
func (c *XDPoS_v1) VerifyUncles(chain consensus.ChainReader, block *types.Block) error { func (x *XDPoS_v1) VerifyUncles(chain consensus.ChainReader, block *types.Block) error {
if len(block.Uncles()) > 0 { if len(block.Uncles()) > 0 {
return errors.New("uncles not allowed") return errors.New("uncles not allowed")
} }
@ -566,8 +523,8 @@ func (c *XDPoS_v1) VerifyUncles(chain consensus.ChainReader, block *types.Block)
// VerifySeal implements consensus.Engine, checking whether the signature contained // VerifySeal implements consensus.Engine, checking whether the signature contained
// in the header satisfies the consensus protocol requirements. // in the header satisfies the consensus protocol requirements.
func (c *XDPoS_v1) VerifySeal(chain consensus.ChainReader, header *types.Header) error { func (x *XDPoS_v1) VerifySeal(chain consensus.ChainReader, header *types.Header) error {
return c.verifySeal(chain, header, nil, true) return x.verifySeal(chain, header, nil, true)
} }
// verifySeal checks whether the signature contained in the header satisfies the // verifySeal checks whether the signature contained in the header satisfies the
@ -576,20 +533,20 @@ func (c *XDPoS_v1) VerifySeal(chain consensus.ChainReader, header *types.Header)
// from. // from.
// verifySeal also checks the pair of creator-validator set in the header satisfies // verifySeal also checks the pair of creator-validator set in the header satisfies
// the double validation. // the double validation.
func (c *XDPoS_v1) verifySeal(chain consensus.ChainReader, header *types.Header, parents []*types.Header, fullVerify bool) error { func (x *XDPoS_v1) verifySeal(chain consensus.ChainReader, header *types.Header, parents []*types.Header, fullVerify bool) error {
// Verifying the genesis block is not supported // Verifying the genesis block is not supported
number := header.Number.Uint64() number := header.Number.Uint64()
if number == 0 { if number == 0 {
return utils.ErrUnknownBlock return utils.ErrUnknownBlock
} }
// Retrieve the snapshot needed to verify this header and cache it // Retrieve the snapshot needed to verify this header and cache it
snap, err := c.snapshot(chain, number-1, header.ParentHash, parents) snap, err := x.snapshot(chain, number-1, header.ParentHash, parents)
if err != nil { if err != nil {
return err return err
} }
// Resolve the authorization key and check against signers // Resolve the authorization key and check against signers
creator, err := ecrecover(header, c.signatures) creator, err := ecrecover(header, x.signatures)
if err != nil { if err != nil {
return err return err
} }
@ -599,7 +556,7 @@ func (c *XDPoS_v1) verifySeal(chain consensus.ChainReader, header *types.Header,
} else { } else {
parent = chain.GetHeader(header.ParentHash, number-1) parent = chain.GetHeader(header.ParentHash, number-1)
} }
difficulty := c.calcDifficulty(chain, parent, creator) difficulty := x.calcDifficulty(chain, parent, creator)
log.Debug("verify seal block", "number", header.Number, "hash", header.Hash(), "block difficulty", header.Difficulty, "calc difficulty", difficulty, "creator", creator) log.Debug("verify seal block", "number", header.Number, "hash", header.Hash(), "block difficulty", header.Difficulty, "calc difficulty", difficulty, "creator", creator)
// Ensure that the block's difficulty is meaningful (may not be correct at this point) // Ensure that the block's difficulty is meaningful (may not be correct at this point)
if number > 0 { if number > 0 {
@ -607,7 +564,7 @@ func (c *XDPoS_v1) verifySeal(chain consensus.ChainReader, header *types.Header,
return utils.ErrInvalidDifficulty return utils.ErrInvalidDifficulty
} }
} }
masternodes := c.GetMasternodes(chain, header) masternodes := x.GetMasternodes(chain, header)
mstring := []string{} mstring := []string{}
for _, m := range masternodes { for _, m := range masternodes {
mstring = append(mstring, m.String()) mstring = append(mstring, m.String())
@ -636,7 +593,7 @@ func (c *XDPoS_v1) verifySeal(chain consensus.ChainReader, header *types.Header,
// There is only case that we don't allow signer to create two continuous blocks. // There is only case that we don't allow signer to create two continuous blocks.
if limit := uint64(2); seen > number-limit { if limit := uint64(2); seen > number-limit {
// Only take into account the non-epoch blocks // Only take into account the non-epoch blocks
if number%c.config.Epoch != 0 { if number%x.config.Epoch != 0 {
return utils.ErrUnauthorized return utils.ErrUnauthorized
} }
} }
@ -646,14 +603,14 @@ func (c *XDPoS_v1) verifySeal(chain consensus.ChainReader, header *types.Header,
// header must contain validator info following double validation design // header must contain validator info following double validation design
// start checking from epoch 2nd. // start checking from epoch 2nd.
if header.Number.Uint64() > c.config.Epoch && fullVerify { if header.Number.Uint64() > x.config.Epoch && fullVerify {
validator, err := c.RecoverValidator(header) validator, err := x.RecoverValidator(header)
if err != nil { if err != nil {
return err return err
} }
// verify validator // verify validator
assignedValidator, err := c.GetValidator(creator, chain, header) assignedValidator, err := x.GetValidator(creator, chain, header)
if err != nil { if err != nil {
return err return err
} }
@ -665,8 +622,8 @@ func (c *XDPoS_v1) verifySeal(chain consensus.ChainReader, header *types.Header,
return nil return nil
} }
func (c *XDPoS_v1) GetValidator(creator common.Address, chain consensus.ChainReader, header *types.Header) (common.Address, error) { func (x *XDPoS_v1) GetValidator(creator common.Address, chain consensus.ChainReader, header *types.Header) (common.Address, error) {
epoch := c.config.Epoch epoch := x.config.Epoch
no := header.Number.Uint64() no := header.Number.Uint64()
cpNo := no cpNo := no
if no%epoch != 0 { if no%epoch != 0 {
@ -692,23 +649,23 @@ func (c *XDPoS_v1) GetValidator(creator common.Address, chain consensus.ChainRea
// Prepare implements consensus.Engine, preparing all the consensus fields of the // Prepare implements consensus.Engine, preparing all the consensus fields of the
// header for running the transactions on top. // header for running the transactions on top.
func (c *XDPoS_v1) Prepare(chain consensus.ChainReader, header *types.Header) error { func (x *XDPoS_v1) Prepare(chain consensus.ChainReader, header *types.Header) error {
// If the block isn't a checkpoint, cast a random vote (good enough for now) // If the block isn't a checkpoint, cast a random vote (good enough for now)
header.Coinbase = common.Address{} header.Coinbase = common.Address{}
header.Nonce = types.BlockNonce{} header.Nonce = types.BlockNonce{}
number := header.Number.Uint64() number := header.Number.Uint64()
// Assemble the voting snapshot to check which votes make sense // Assemble the voting snapshot to check which votes make sense
snap, err := c.snapshot(chain, number-1, header.ParentHash, nil) snap, err := x.snapshot(chain, number-1, header.ParentHash, nil)
if err != nil { if err != nil {
return err return err
} }
if number%c.config.Epoch != 0 { if number%x.config.Epoch != 0 {
c.lock.RLock() x.lock.RLock()
// Gather all the proposals that make sense voting on // Gather all the proposals that make sense voting on
addresses := make([]common.Address, 0, len(c.proposals)) addresses := make([]common.Address, 0, len(x.proposals))
for address, authorize := range c.proposals { for address, authorize := range x.proposals {
if snap.validVote(address, authorize) { if snap.validVote(address, authorize) {
addresses = append(addresses, address) addresses = append(addresses, address)
} }
@ -716,20 +673,20 @@ func (c *XDPoS_v1) Prepare(chain consensus.ChainReader, header *types.Header) er
// If there's pending proposals, cast a vote on them // If there's pending proposals, cast a vote on them
if len(addresses) > 0 { if len(addresses) > 0 {
header.Coinbase = addresses[rand.Intn(len(addresses))] header.Coinbase = addresses[rand.Intn(len(addresses))]
if c.proposals[header.Coinbase] { if x.proposals[header.Coinbase] {
copy(header.Nonce[:], utils.NonceAuthVote) copy(header.Nonce[:], utils.NonceAuthVote)
} else { } else {
copy(header.Nonce[:], utils.NonceDropVote) copy(header.Nonce[:], utils.NonceDropVote)
} }
} }
c.lock.RUnlock() x.lock.RUnlock()
} }
parent := chain.GetHeader(header.ParentHash, number-1) parent := chain.GetHeader(header.ParentHash, number-1)
if parent == nil { if parent == nil {
return consensus.ErrUnknownAncestor return consensus.ErrUnknownAncestor
} }
// Set the correct difficulty // Set the correct difficulty
header.Difficulty = c.calcDifficulty(chain, parent, c.signer) header.Difficulty = x.calcDifficulty(chain, parent, x.signer)
log.Debug("CalcDifficulty ", "number", header.Number, "difficulty", header.Difficulty) log.Debug("CalcDifficulty ", "number", header.Number, "difficulty", header.Difficulty)
// Ensure the extra data has all it's components // Ensure the extra data has all it's components
if len(header.Extra) < utils.ExtraVanity { if len(header.Extra) < utils.ExtraVanity {
@ -737,14 +694,14 @@ func (c *XDPoS_v1) Prepare(chain consensus.ChainReader, header *types.Header) er
} }
header.Extra = header.Extra[:utils.ExtraVanity] header.Extra = header.Extra[:utils.ExtraVanity]
masternodes := snap.GetSigners() masternodes := snap.GetSigners()
if number >= c.config.Epoch && number%c.config.Epoch == 0 { if number >= x.config.Epoch && number%x.config.Epoch == 0 {
if c.HookPenalty != nil || c.HookPenaltyTIPSigning != nil { if x.HookPenalty != nil || x.HookPenaltyTIPSigning != nil {
var penMasternodes []common.Address var penMasternodes []common.Address
var err error var err error
if chain.Config().IsTIPSigning(header.Number) { if chain.Config().IsTIPSigning(header.Number) {
penMasternodes, err = c.HookPenaltyTIPSigning(chain, header, masternodes) penMasternodes, err = x.HookPenaltyTIPSigning(chain, header, masternodes)
} else { } else {
penMasternodes, err = c.HookPenalty(chain, number) penMasternodes, err = x.HookPenalty(chain, number)
} }
if err != nil { if err != nil {
return err return err
@ -760,15 +717,15 @@ func (c *XDPoS_v1) Prepare(chain consensus.ChainReader, header *types.Header) er
} }
// Prevent penalized masternode(s) within 4 recent epochs // Prevent penalized masternode(s) within 4 recent epochs
for i := 1; i <= common.LimitPenaltyEpoch; i++ { for i := 1; i <= common.LimitPenaltyEpoch; i++ {
if number > uint64(i)*c.config.Epoch { if number > uint64(i)*x.config.Epoch {
masternodes = removePenaltiesFromBlock(chain, masternodes, number-uint64(i)*c.config.Epoch) masternodes = removePenaltiesFromBlock(chain, masternodes, number-uint64(i)*x.config.Epoch)
} }
} }
for _, masternode := range masternodes { for _, masternode := range masternodes {
header.Extra = append(header.Extra, masternode[:]...) header.Extra = append(header.Extra, masternode[:]...)
} }
if c.HookValidator != nil { if x.HookValidator != nil {
validators, err := c.HookValidator(header, masternodes) validators, err := x.HookValidator(header, masternodes)
if err != nil { if err != nil {
return err return err
} }
@ -782,18 +739,18 @@ func (c *XDPoS_v1) Prepare(chain consensus.ChainReader, header *types.Header) er
// Ensure the timestamp has the correct delay // Ensure the timestamp has the correct delay
header.Time = new(big.Int).Add(parent.Time, new(big.Int).SetUint64(c.config.Period)) header.Time = new(big.Int).Add(parent.Time, new(big.Int).SetUint64(x.config.Period))
if header.Time.Int64() < time.Now().Unix() { if header.Time.Int64() < time.Now().Unix() {
header.Time = big.NewInt(time.Now().Unix()) header.Time = big.NewInt(time.Now().Unix())
} }
return nil return nil
} }
func (c *XDPoS_v1) UpdateMasternodes(chain consensus.ChainReader, header *types.Header, ms []utils.Masternode) error { func (x *XDPoS_v1) UpdateMasternodes(chain consensus.ChainReader, header *types.Header, ms []utils.Masternode) error {
number := header.Number.Uint64() number := header.Number.Uint64()
log.Trace("take snapshot", "number", number, "hash", header.Hash()) log.Trace("take snapshot", "number", number, "hash", header.Hash())
// get snapshot // get snapshot
snap, err := c.snapshot(chain, number, header.Hash(), nil) snap, err := x.snapshot(chain, number, header.Hash(), nil)
if err != nil { if err != nil {
return err return err
} }
@ -806,22 +763,22 @@ func (c *XDPoS_v1) UpdateMasternodes(chain consensus.ChainReader, header *types.
for _, n := range ms { for _, n := range ms {
nm = append(nm, n.Address.String()) nm = append(nm, n.Address.String())
} }
c.recents.Add(snap.Hash, snap) x.recents.Add(snap.Hash, snap)
log.Info("New set of masternodes has been updated to snapshot", "number", snap.Number, "hash", snap.Hash, "new masternodes", nm) log.Info("New set of masternodes has been updated to snapshot", "number", snap.Number, "hash", snap.Hash, "new masternodes", nm)
return nil return nil
} }
// Finalize implements consensus.Engine, ensuring no uncles are set, nor block // Finalize implements consensus.Engine, ensuring no uncles are set, nor block
// rewards given, and returns the final block. // rewards given, and returns the final block.
func (c *XDPoS_v1) Finalize(chain consensus.ChainReader, header *types.Header, state *state.StateDB, parentState *state.StateDB, txs []*types.Transaction, uncles []*types.Header, receipts []*types.Receipt) (*types.Block, error) { func (x *XDPoS_v1) Finalize(chain consensus.ChainReader, header *types.Header, state *state.StateDB, parentState *state.StateDB, txs []*types.Transaction, uncles []*types.Header, receipts []*types.Receipt) (*types.Block, error) {
// set block reward // set block reward
number := header.Number.Uint64() number := header.Number.Uint64()
rCheckpoint := chain.Config().XDPoS.RewardCheckpoint rCheckpoint := chain.Config().XDPoS.RewardCheckpoint
// _ = c.CacheData(header, txs, receipts) // _ = c.CacheData(header, txs, receipts)
if c.HookReward != nil && number%rCheckpoint == 0 { if x.HookReward != nil && number%rCheckpoint == 0 {
err, rewards := c.HookReward(chain, state, parentState, header) err, rewards := x.HookReward(chain, state, parentState, header)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -846,17 +803,17 @@ func (c *XDPoS_v1) Finalize(chain consensus.ChainReader, header *types.Header, s
// Authorize injects a private key into the consensus engine to mint new blocks // Authorize injects a private key into the consensus engine to mint new blocks
// with. // with.
func (c *XDPoS_v1) Authorize(signer common.Address, signFn clique.SignerFn) { func (x *XDPoS_v1) Authorize(signer common.Address, signFn clique.SignerFn) {
c.lock.Lock() x.lock.Lock()
defer c.lock.Unlock() defer x.lock.Unlock()
c.signer = signer x.signer = signer
c.signFn = signFn x.signFn = signFn
} }
// Seal implements consensus.Engine, attempting to create a sealed block using // Seal implements consensus.Engine, attempting to create a sealed block using
// the local signing credentials. // the local signing credentials.
func (c *XDPoS_v1) Seal(chain consensus.ChainReader, block *types.Block, stop <-chan struct{}) (*types.Block, error) { func (x *XDPoS_v1) Seal(chain consensus.ChainReader, block *types.Block, stop <-chan struct{}) (*types.Block, error) {
header := block.Header() header := block.Header()
// Sealing the genesis block is not supported // Sealing the genesis block is not supported
@ -866,20 +823,20 @@ func (c *XDPoS_v1) Seal(chain consensus.ChainReader, block *types.Block, stop <-
} }
// For 0-period chains, refuse to seal empty blocks (no reward but would spin sealing) // For 0-period chains, refuse to seal empty blocks (no reward but would spin sealing)
// checkpoint blocks have no tx // checkpoint blocks have no tx
if c.config.Period == 0 && len(block.Transactions()) == 0 && number%c.config.Epoch != 0 { if x.config.Period == 0 && len(block.Transactions()) == 0 && number%x.config.Epoch != 0 {
return nil, utils.ErrWaitTransactions return nil, utils.ErrWaitTransactions
} }
// Don't hold the signer fields for the entire sealing procedure // Don't hold the signer fields for the entire sealing procedure
c.lock.RLock() x.lock.RLock()
signer, signFn := c.signer, c.signFn signer, signFn := x.signer, x.signFn
c.lock.RUnlock() x.lock.RUnlock()
// Bail out if we're unauthorized to sign a block // Bail out if we're unauthorized to sign a block
snap, err := c.snapshot(chain, number-1, header.ParentHash, nil) snap, err := x.snapshot(chain, number-1, header.ParentHash, nil)
if err != nil { if err != nil {
return nil, err return nil, err
} }
masternodes := c.GetMasternodes(chain, header) masternodes := x.GetMasternodes(chain, header)
if _, authorized := snap.Signers[signer]; !authorized { if _, authorized := snap.Signers[signer]; !authorized {
valid := false valid := false
for _, m := range masternodes { for _, m := range masternodes {
@ -901,7 +858,7 @@ func (c *XDPoS_v1) Seal(chain consensus.ChainReader, block *types.Block, stop <-
// There is only case that we don't allow signer to create two continuous blocks. // There is only case that we don't allow signer to create two continuous blocks.
if limit := uint64(2); number < limit || seen > number-limit { if limit := uint64(2); number < limit || seen > number-limit {
// Only take into account the non-epoch blocks // Only take into account the non-epoch blocks
if number%c.config.Epoch != 0 { if number%x.config.Epoch != 0 {
log.Info("Signed recently, must wait for others ", "len(masternodes)", len(masternodes), "number", number, "limit", limit, "seen", seen, "recent", recent.String(), "snap.Recents", snap.Recents) log.Info("Signed recently, must wait for others ", "len(masternodes)", len(masternodes), "number", number, "limit", limit, "seen", seen, "recent", recent.String(), "snap.Recents", snap.Recents)
<-stop <-stop
return nil, nil return nil, nil
@ -916,12 +873,12 @@ func (c *XDPoS_v1) Seal(chain consensus.ChainReader, block *types.Block, stop <-
default: default:
} }
// Sign all the things! // Sign all the things!
sighash, err := signFn(accounts.Account{Address: signer}, sigHash(header).Bytes()) sighash, err := signFn(accounts.Account{Address: signer}, utils.SigHash(header).Bytes())
if err != nil { if err != nil {
return nil, err return nil, err
} }
copy(header.Extra[len(header.Extra)-utils.ExtraSeal:], sighash) copy(header.Extra[len(header.Extra)-utils.ExtraSeal:], sighash)
m2, err := c.GetValidator(signer, chain, header) m2, err := x.GetValidator(signer, chain, header)
if err != nil { if err != nil {
return nil, fmt.Errorf("can't get block validator: %v", err) return nil, fmt.Errorf("can't get block validator: %v", err)
} }
@ -934,30 +891,30 @@ func (c *XDPoS_v1) Seal(chain consensus.ChainReader, block *types.Block, stop <-
// CalcDifficulty is the difficulty adjustment algorithm. It returns the difficulty // CalcDifficulty is the difficulty adjustment algorithm. It returns the difficulty
// that a new block should have based on the previous blocks in the chain and the // that a new block should have based on the previous blocks in the chain and the
// current signer. // current signer.
func (c *XDPoS_v1) CalcDifficulty(chain consensus.ChainReader, time uint64, parent *types.Header) *big.Int { func (x *XDPoS_v1) CalcDifficulty(chain consensus.ChainReader, time uint64, parent *types.Header) *big.Int {
return c.calcDifficulty(chain, parent, c.signer) return x.calcDifficulty(chain, parent, x.signer)
} }
func (c *XDPoS_v1) calcDifficulty(chain consensus.ChainReader, parent *types.Header, signer common.Address) *big.Int { func (x *XDPoS_v1) calcDifficulty(chain consensus.ChainReader, parent *types.Header, signer common.Address) *big.Int {
// If we're running a engine faking, skip calculation // If we're running a engine faking, skip calculation
if c.config.SkipValidation { if x.config.SkipValidation {
return big.NewInt(1) return big.NewInt(1)
} }
len, preIndex, curIndex, _, err := c.YourTurn(chain, parent, signer) len, preIndex, curIndex, _, err := x.YourTurn(chain, parent, signer)
if err != nil { if err != nil {
return big.NewInt(int64(len + curIndex - preIndex)) return big.NewInt(int64(len + curIndex - preIndex))
} }
return big.NewInt(int64(len - utils.Hop(len, preIndex, curIndex))) return big.NewInt(int64(len - utils.Hop(len, preIndex, curIndex)))
} }
func (c *XDPoS_v1) RecoverSigner(header *types.Header) (common.Address, error) { func (x *XDPoS_v1) RecoverSigner(header *types.Header) (common.Address, error) {
return ecrecover(header, c.signatures) return ecrecover(header, x.signatures)
} }
func (c *XDPoS_v1) RecoverValidator(header *types.Header) (common.Address, error) { func (x *XDPoS_v1) RecoverValidator(header *types.Header) (common.Address, error) {
// If the signature's already cached, return that // If the signature's already cached, return that
hash := header.Hash() hash := header.Hash()
if address, known := c.validatorSignatures.Get(hash); known { if address, known := x.validatorSignatures.Get(hash); known {
return address.(common.Address), nil return address.(common.Address), nil
} }
// Retrieve the signature from the header.Validator // Retrieve the signature from the header.Validator
@ -966,19 +923,19 @@ func (c *XDPoS_v1) RecoverValidator(header *types.Header) (common.Address, error
return common.Address{}, consensus.ErrFailValidatorSignature return common.Address{}, consensus.ErrFailValidatorSignature
} }
// Recover the public key and the Ethereum address // Recover the public key and the Ethereum address
pubkey, err := crypto.Ecrecover(sigHash(header).Bytes(), header.Validator) pubkey, err := crypto.Ecrecover(utils.SigHash(header).Bytes(), header.Validator)
if err != nil { if err != nil {
return common.Address{}, err return common.Address{}, err
} }
var signer common.Address var signer common.Address
copy(signer[:], crypto.Keccak256(pubkey[1:])[12:]) copy(signer[:], crypto.Keccak256(pubkey[1:])[12:])
c.validatorSignatures.Add(hash, signer) x.validatorSignatures.Add(hash, signer)
return signer, nil return signer, nil
} }
// Get master nodes over extra data of previous checkpoint block. // Get master nodes over extra data of previous checkpoint block.
func (c *XDPoS_v1) GetMasternodesFromCheckpointHeader(preCheckpointHeader *types.Header, n, e uint64) []common.Address { func (x *XDPoS_v1) GetMasternodesFromCheckpointHeader(preCheckpointHeader *types.Header, n, e uint64) []common.Address {
if preCheckpointHeader == nil { if preCheckpointHeader == nil {
log.Info("Previous checkpoint's header is empty", "block number", n, "epoch", e) log.Info("Previous checkpoint's header is empty", "block number", n, "epoch", e)
return []common.Address{} return []common.Address{}
@ -991,8 +948,8 @@ func (c *XDPoS_v1) GetMasternodesFromCheckpointHeader(preCheckpointHeader *types
return masternodes return masternodes
} }
func (c *XDPoS_v1) GetDb() ethdb.Database { func (x *XDPoS_v1) GetDb() ethdb.Database {
return c.db return x.db
} }
// Extract validators from byte array. // Extract validators from byte array.
@ -1034,23 +991,23 @@ func GetM1M2FromCheckpointHeader(checkpointHeader *types.Header, currentHeader *
return m1m2, nil return m1m2, nil
} }
func (c *XDPoS_v1) getSignersFromContract(chain consensus.ChainReader, checkpointHeader *types.Header) ([]common.Address, error) { func (x *XDPoS_v1) getSignersFromContract(chain consensus.ChainReader, checkpointHeader *types.Header) ([]common.Address, error) {
startGapBlockHeader := checkpointHeader startGapBlockHeader := checkpointHeader
number := checkpointHeader.Number.Uint64() number := checkpointHeader.Number.Uint64()
for step := uint64(1); step <= chain.Config().XDPoS.Gap; step++ { for step := uint64(1); step <= chain.Config().XDPoS.Gap; step++ {
startGapBlockHeader = chain.GetHeader(startGapBlockHeader.ParentHash, number-step) startGapBlockHeader = chain.GetHeader(startGapBlockHeader.ParentHash, number-step)
} }
signers, err := c.HookGetSignersFromContract(startGapBlockHeader.Hash()) signers, err := x.HookGetSignersFromContract(startGapBlockHeader.Hash())
if err != nil { if err != nil {
return []common.Address{}, fmt.Errorf("Can't get signers from Smart Contract . Err: %v", err) return []common.Address{}, fmt.Errorf("Can't get signers from Smart Contract . Err: %v", err)
} }
return signers, nil return signers, nil
} }
func NewFaker(db ethdb.Database) *XDPoS_v1 { func NewFaker(db ethdb.Database, config *params.XDPoSConfig) *XDPoS_v1 {
var fakeEngine *XDPoS_v1 var fakeEngine *XDPoS_v1
// Set any missing consensus parameters to their defaults // Set any missing consensus parameters to their defaults
conf := params.TestXDPoSMockChainConfig.XDPoS conf := config
// Allocate the snapshot caches and create the engine // Allocate the snapshot caches and create the engine
recents, _ := lru.NewARC(utils.InmemorySnapshots) recents, _ := lru.NewARC(utils.InmemorySnapshots)

View file

@ -1 +1,42 @@
package engine_v2 package engine_v2
import (
"github.com/XinFinOrg/XDPoSChain/common"
"github.com/XinFinOrg/XDPoSChain/consensus"
"github.com/XinFinOrg/XDPoSChain/core/types"
"github.com/XinFinOrg/XDPoSChain/ethdb"
"github.com/XinFinOrg/XDPoSChain/params"
)
type XDPoS_v2 struct {
config *params.XDPoSConfig // Consensus engine configuration parameters
db ethdb.Database // Database to store and retrieve snapshot checkpoints
}
func New(config *params.XDPoSConfig, db ethdb.Database) *XDPoS_v2 {
return &XDPoS_v2{
config: config,
db: db,
}
}
func NewFaker(db ethdb.Database, config *params.XDPoSConfig) *XDPoS_v2 {
var fakeEngine *XDPoS_v2
// Set any missing consensus parameters to their defaults
conf := config
// Allocate the snapshot caches and create the engine
fakeEngine = &XDPoS_v2{
config: conf,
db: db,
}
return fakeEngine
}
func (consensus *XDPoS_v2) Author(header *types.Header) (common.Address, error) {
return common.Address{}, nil
}
func (consensus *XDPoS_v2) VerifyHeader(chain consensus.ChainReader, header *types.Header, fullVerify bool) error {
return nil
}

View file

@ -9,8 +9,10 @@ import (
"github.com/XinFinOrg/XDPoSChain/common" "github.com/XinFinOrg/XDPoSChain/common"
"github.com/XinFinOrg/XDPoSChain/core/types" "github.com/XinFinOrg/XDPoSChain/core/types"
"github.com/XinFinOrg/XDPoSChain/crypto/sha3"
"github.com/XinFinOrg/XDPoSChain/log" "github.com/XinFinOrg/XDPoSChain/log"
"github.com/XinFinOrg/XDPoSChain/params" "github.com/XinFinOrg/XDPoSChain/params"
"github.com/XinFinOrg/XDPoSChain/rlp"
) )
func Position(list []common.Address, x common.Address) int { func Position(list []common.Address, x common.Address) int {
@ -109,3 +111,41 @@ func CompareSignersLists(list1 []common.Address, list2 []common.Address) bool {
}) })
return reflect.DeepEqual(list1, list2) return reflect.DeepEqual(list1, list2)
} }
// SignerFn is a signer callback function to request a hash to be signed by a
// backing account.
//type SignerFn func(accounts.Account, []byte) ([]byte, error)
// sigHash returns the hash which is used as input for the delegated-proof-of-stake
// signing. It is the hash of the entire header apart from the 65 byte signature
// contained at the end of the extra data.
//
// Note, the method requires the extra data to be at least 65 bytes, otherwise it
// panics. This is done to avoid accidentally using both forms (signature present
// or not), which could be abused to produce different hashes for the same header.
func SigHash(header *types.Header) (hash common.Hash) {
hasher := sha3.NewKeccak256()
err := rlp.Encode(hasher, []interface{}{
header.ParentHash,
header.UncleHash,
header.Coinbase,
header.Root,
header.TxHash,
header.ReceiptHash,
header.Bloom,
header.Difficulty,
header.Number,
header.GasLimit,
header.GasUsed,
header.Time,
header.Extra[:len(header.Extra)-65], // Yes, this will panic if extra is too short
header.MixDigest,
header.Nonce,
})
if err != nil {
log.Debug("Fail to encode", err)
}
hasher.Sum(hash[:0])
return hash
}

View file

@ -18,12 +18,13 @@
package consensus package consensus
import ( import (
"math/big"
"github.com/XinFinOrg/XDPoSChain/common" "github.com/XinFinOrg/XDPoSChain/common"
"github.com/XinFinOrg/XDPoSChain/core/state" "github.com/XinFinOrg/XDPoSChain/core/state"
"github.com/XinFinOrg/XDPoSChain/core/types" "github.com/XinFinOrg/XDPoSChain/core/types"
"github.com/XinFinOrg/XDPoSChain/params" "github.com/XinFinOrg/XDPoSChain/params"
"github.com/XinFinOrg/XDPoSChain/rpc" "github.com/XinFinOrg/XDPoSChain/rpc"
"math/big"
) )
// ChainReader defines a small collection of methods needed to access the local // ChainReader defines a small collection of methods needed to access the local

View file

@ -28,6 +28,7 @@ import (
"github.com/XinFinOrg/XDPoSChain/common" "github.com/XinFinOrg/XDPoSChain/common"
"github.com/XinFinOrg/XDPoSChain/core" "github.com/XinFinOrg/XDPoSChain/core"
"github.com/XinFinOrg/XDPoSChain/crypto" "github.com/XinFinOrg/XDPoSChain/crypto"
"github.com/XinFinOrg/XDPoSChain/params"
) )
var ( var (
@ -36,7 +37,7 @@ var (
) )
func TestBlockSigner(t *testing.T) { func TestBlockSigner(t *testing.T) {
contractBackend := backends.NewXDCSimulatedBackend(core.GenesisAlloc{addr: {Balance: big.NewInt(1000000000)}}, 10000000) contractBackend := backends.NewXDCSimulatedBackend(core.GenesisAlloc{addr: {Balance: big.NewInt(1000000000)}}, 10000000, params.TestXDPoSMockChainConfig)
transactOpts := bind.NewKeyedTransactor(key) transactOpts := bind.NewKeyedTransactor(key)
blockSignerAddress, blockSigner, err := DeployBlockSigner(transactOpts, contractBackend, big.NewInt(99)) blockSignerAddress, blockSigner, err := DeployBlockSigner(transactOpts, contractBackend, big.NewInt(99))

View file

@ -30,6 +30,7 @@ import (
"github.com/XinFinOrg/XDPoSChain/contracts/chequebook/contract" "github.com/XinFinOrg/XDPoSChain/contracts/chequebook/contract"
"github.com/XinFinOrg/XDPoSChain/core" "github.com/XinFinOrg/XDPoSChain/core"
"github.com/XinFinOrg/XDPoSChain/crypto" "github.com/XinFinOrg/XDPoSChain/crypto"
"github.com/XinFinOrg/XDPoSChain/params"
) )
var ( var (
@ -46,7 +47,7 @@ func newTestBackend() *backends.SimulatedBackend {
addr0: {Balance: big.NewInt(1000000000)}, addr0: {Balance: big.NewInt(1000000000)},
addr1: {Balance: big.NewInt(1000000000)}, addr1: {Balance: big.NewInt(1000000000)},
addr2: {Balance: big.NewInt(1000000000)}, addr2: {Balance: big.NewInt(1000000000)},
}, 10000000) }, 10000000, params.TestXDPoSMockChainConfig)
} }
func deploy(prvKey *ecdsa.PrivateKey, amount *big.Int, backend *backends.SimulatedBackend) (common.Address, error) { func deploy(prvKey *ecdsa.PrivateKey, amount *big.Int, backend *backends.SimulatedBackend) (common.Address, error) {

View file

@ -25,6 +25,7 @@ import (
"github.com/XinFinOrg/XDPoSChain/contracts/ens/contract" "github.com/XinFinOrg/XDPoSChain/contracts/ens/contract"
"github.com/XinFinOrg/XDPoSChain/core" "github.com/XinFinOrg/XDPoSChain/core"
"github.com/XinFinOrg/XDPoSChain/crypto" "github.com/XinFinOrg/XDPoSChain/crypto"
"github.com/XinFinOrg/XDPoSChain/params"
) )
var ( var (
@ -35,7 +36,7 @@ var (
) )
func TestENS(t *testing.T) { func TestENS(t *testing.T) {
contractBackend := backends.NewXDCSimulatedBackend(core.GenesisAlloc{addr: {Balance: big.NewInt(1000000000)}}, 10000000) contractBackend := backends.NewXDCSimulatedBackend(core.GenesisAlloc{addr: {Balance: big.NewInt(1000000000)}}, 10000000, params.TestXDPoSMockChainConfig)
transactOpts := bind.NewKeyedTransactor(key) transactOpts := bind.NewKeyedTransactor(key)
ensAddr, ens, err := DeployENS(transactOpts, contractBackend) ensAddr, ens, err := DeployENS(transactOpts, contractBackend)

View file

@ -28,6 +28,7 @@ import (
"github.com/XinFinOrg/XDPoSChain/core" "github.com/XinFinOrg/XDPoSChain/core"
"github.com/XinFinOrg/XDPoSChain/core/types" "github.com/XinFinOrg/XDPoSChain/core/types"
"github.com/XinFinOrg/XDPoSChain/crypto" "github.com/XinFinOrg/XDPoSChain/crypto"
"github.com/XinFinOrg/XDPoSChain/params"
) )
var ( var (
@ -40,7 +41,7 @@ var (
) )
func TestRandomize(t *testing.T) { func TestRandomize(t *testing.T) {
contractBackend := backends.NewXDCSimulatedBackend(core.GenesisAlloc{addr: {Balance: big.NewInt(100000000000000)}}, 10000000) contractBackend := backends.NewXDCSimulatedBackend(core.GenesisAlloc{addr: {Balance: big.NewInt(100000000000000)}}, 10000000, params.TestXDPoSMockChainConfig)
transactOpts := bind.NewKeyedTransactor(key) transactOpts := bind.NewKeyedTransactor(key)
transactOpts.GasLimit = 1000000 transactOpts.GasLimit = 1000000

View file

@ -32,6 +32,7 @@ import (
"github.com/XinFinOrg/XDPoSChain/core" "github.com/XinFinOrg/XDPoSChain/core"
"github.com/XinFinOrg/XDPoSChain/core/types" "github.com/XinFinOrg/XDPoSChain/core/types"
"github.com/XinFinOrg/XDPoSChain/crypto" "github.com/XinFinOrg/XDPoSChain/crypto"
"github.com/XinFinOrg/XDPoSChain/params"
) )
var ( var (
@ -47,7 +48,7 @@ var (
func getCommonBackend() *backends.SimulatedBackend { func getCommonBackend() *backends.SimulatedBackend {
genesis := core.GenesisAlloc{acc1Addr: {Balance: big.NewInt(1000000000000)}} genesis := core.GenesisAlloc{acc1Addr: {Balance: big.NewInt(1000000000000)}}
backend := backends.NewXDCSimulatedBackend(genesis, 10000000) backend := backends.NewXDCSimulatedBackend(genesis, 10000000, params.TestXDPoSMockChainConfig)
backend.Commit() backend.Commit()
return backend return backend

View file

@ -30,6 +30,7 @@ import (
"github.com/XinFinOrg/XDPoSChain/core" "github.com/XinFinOrg/XDPoSChain/core"
"github.com/XinFinOrg/XDPoSChain/crypto" "github.com/XinFinOrg/XDPoSChain/crypto"
"github.com/XinFinOrg/XDPoSChain/log" "github.com/XinFinOrg/XDPoSChain/log"
"github.com/XinFinOrg/XDPoSChain/params"
) )
var ( var (
@ -46,7 +47,7 @@ var (
) )
func TestValidator(t *testing.T) { func TestValidator(t *testing.T) {
contractBackend := backends.NewXDCSimulatedBackend(core.GenesisAlloc{addr: {Balance: big.NewInt(1000000000)}}, 10000000) contractBackend := backends.NewXDCSimulatedBackend(core.GenesisAlloc{addr: {Balance: big.NewInt(1000000000)}}, 10000000, params.TestXDPoSMockChainConfig)
transactOpts := bind.NewKeyedTransactor(key) transactOpts := bind.NewKeyedTransactor(key)
validatorCap := new(big.Int) validatorCap := new(big.Int)
@ -86,7 +87,7 @@ func TestRewardBalance(t *testing.T) {
acc1Addr: {Balance: new(big.Int).SetUint64(10000000)}, acc1Addr: {Balance: new(big.Int).SetUint64(10000000)},
acc2Addr: {Balance: new(big.Int).SetUint64(10000000)}, acc2Addr: {Balance: new(big.Int).SetUint64(10000000)},
acc4Addr: {Balance: new(big.Int).SetUint64(10000000)}, acc4Addr: {Balance: new(big.Int).SetUint64(10000000)},
}, 42000000) }, 42000000, params.TestXDPoSMockChainConfig)
acc1Opts := bind.NewKeyedTransactor(acc1Key) acc1Opts := bind.NewKeyedTransactor(acc1Key)
acc2Opts := bind.NewKeyedTransactor(acc2Key) acc2Opts := bind.NewKeyedTransactor(acc2Key)
accounts := []*bind.TransactOpts{acc1Opts, acc2Opts} accounts := []*bind.TransactOpts{acc1Opts, acc2Opts}

30631
coverage.txt

File diff suppressed because it is too large Load diff

2
go.mod
View file

@ -51,7 +51,7 @@ require (
github.com/rs/cors v1.6.0 github.com/rs/cors v1.6.0
github.com/steakknife/bloomfilter v0.0.0-20180922174646-6819c0d2a570 github.com/steakknife/bloomfilter v0.0.0-20180922174646-6819c0d2a570
github.com/steakknife/hamming v0.0.0-20180906055917-c99c65617cd3 // indirect github.com/steakknife/hamming v0.0.0-20180906055917-c99c65617cd3 // indirect
github.com/stretchr/testify v1.4.0 github.com/stretchr/testify v1.7.0
github.com/syndtr/goleveldb v1.0.1-0.20190923125748-758128399b1d github.com/syndtr/goleveldb v1.0.1-0.20190923125748-758128399b1d
golang.org/x/crypto v0.0.0-20191105034135-c7e5f84aec59 golang.org/x/crypto v0.0.0-20191105034135-c7e5f84aec59
golang.org/x/net v0.0.0-20190912160710-24e19bdeb0f2 golang.org/x/net v0.0.0-20190912160710-24e19bdeb0f2

6
go.sum
View file

@ -87,6 +87,7 @@ github.com/elastic/gosigar v0.10.5 h1:GzPQ+78RaAb4J63unidA/JavQRKrB6s8IOzN6Ib59j
github.com/elastic/gosigar v0.10.5/go.mod h1:cdorVVzy1fhmEqmtgqkoE3bYtCfSCkVyjTyCIo22xvs= github.com/elastic/gosigar v0.10.5/go.mod h1:cdorVVzy1fhmEqmtgqkoE3bYtCfSCkVyjTyCIo22xvs=
github.com/ethereum/go-ethereum v1.9.9 h1:jnoBvjH8aMH++iH14XmiJdAsnRcmZUM+B5fsnEZBVE0= github.com/ethereum/go-ethereum v1.9.9 h1:jnoBvjH8aMH++iH14XmiJdAsnRcmZUM+B5fsnEZBVE0=
github.com/ethereum/go-ethereum v1.9.9/go.mod h1:a9TqabFudpDu1nucId+k9S8R9whYaHnGBLKFouA5EAo= github.com/ethereum/go-ethereum v1.9.9/go.mod h1:a9TqabFudpDu1nucId+k9S8R9whYaHnGBLKFouA5EAo=
github.com/ethereum/go-ethereum v1.10.10 h1:Ft2GcLQrr2M89l49g9NoqgNtJZ9AahzMb7N6VXKZy5U=
github.com/fatih/color v1.3.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fatih/color v1.3.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
github.com/fatih/color v1.6.0 h1:66qjqZk8kalYAvDRtM1AdAJQI0tj4Wrue3Eq3B3pmFU= github.com/fatih/color v1.6.0 h1:66qjqZk8kalYAvDRtM1AdAJQI0tj4Wrue3Eq3B3pmFU=
github.com/fatih/color v1.6.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fatih/color v1.6.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
@ -255,11 +256,14 @@ github.com/steakknife/bloomfilter v0.0.0-20180922174646-6819c0d2a570/go.mod h1:8
github.com/steakknife/hamming v0.0.0-20180906055917-c99c65617cd3 h1:njlZPzLwU639dk2kqnCPPv+wNjq7Xb6EfUxe/oX0/NM= github.com/steakknife/hamming v0.0.0-20180906055917-c99c65617cd3 h1:njlZPzLwU639dk2kqnCPPv+wNjq7Xb6EfUxe/oX0/NM=
github.com/steakknife/hamming v0.0.0-20180906055917-c99c65617cd3/go.mod h1:hpGUWaI9xL8pRQCTXQgocU38Qw1g0Us7n5PxxTwTCYU= github.com/steakknife/hamming v0.0.0-20180906055917-c99c65617cd3/go.mod h1:hpGUWaI9xL8pRQCTXQgocU38Qw1g0Us7n5PxxTwTCYU=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1 h1:2vfRuCMp5sSVIDSqO8oNnWJq7mPa6KVP3iPIwFBuy8A=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/syndtr/goleveldb v1.0.1-0.20190923125748-758128399b1d h1:gZZadD8H+fF+n9CmNhYL1Y0dJB+kLOmKd7FbPJLeGHs= github.com/syndtr/goleveldb v1.0.1-0.20190923125748-758128399b1d h1:gZZadD8H+fF+n9CmNhYL1Y0dJB+kLOmKd7FbPJLeGHs=
github.com/syndtr/goleveldb v1.0.1-0.20190923125748-758128399b1d/go.mod h1:9OrXJhf154huy1nPWmuSrkgjPUtUNhA+Zmy+6AESzuA= github.com/syndtr/goleveldb v1.0.1-0.20190923125748-758128399b1d/go.mod h1:9OrXJhf154huy1nPWmuSrkgjPUtUNhA+Zmy+6AESzuA=
github.com/templexxx/cpufeat v0.0.0-20180724012125-cef66df7f161/go.mod h1:wM7WEvslTq+iOEAMDLSzhVuOt5BRZ05WirO+b09GHQU= github.com/templexxx/cpufeat v0.0.0-20180724012125-cef66df7f161/go.mod h1:wM7WEvslTq+iOEAMDLSzhVuOt5BRZ05WirO+b09GHQU=
@ -347,5 +351,7 @@ gopkg.in/urfave/cli.v1 v1.20.0/go.mod h1:vuBzUtMdQeixQj8LVd+/98pzhxNGQoyuPBlsXHO
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw=
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=

View file

@ -23,6 +23,11 @@ import (
"github.com/XinFinOrg/XDPoSChain/common" "github.com/XinFinOrg/XDPoSChain/common"
) )
const (
ConsensusEngineVersion1 = "v1"
ConsensusEngineVersion2 = "v2"
)
var ( var (
XDCMainnetGenesisHash = common.HexToHash("9326145f8a2c8c00bbe13afc7d7f3d9c868b5ef39d89f2f4e9390e9720298624") // XDC Mainnet genesis hash to enforce below configs on XDCMainnetGenesisHash = common.HexToHash("9326145f8a2c8c00bbe13afc7d7f3d9c868b5ef39d89f2f4e9390e9720298624") // XDC Mainnet genesis hash to enforce below configs on
MainnetGenesisHash = common.HexToHash("8d13370621558f4ed0da587934473c0404729f28b0ff1d50e5fdd840457a2f17") // Mainnet genesis hash to enforce below configs on MainnetGenesisHash = common.HexToHash("8d13370621558f4ed0da587934473c0404729f28b0ff1d50e5fdd840457a2f17") // Mainnet genesis hash to enforce below configs on
@ -111,10 +116,13 @@ var (
// adding flags to the config to also have to set these fields. // adding flags to the config to also have to set these fields.
AllXDPoSProtocolChanges = &ChainConfig{big.NewInt(89), big.NewInt(0), nil, false, big.NewInt(0), common.Hash{}, big.NewInt(0), big.NewInt(0), big.NewInt(0), nil, nil, nil, &XDPoSConfig{Period: 0, Epoch: 30000}} AllXDPoSProtocolChanges = &ChainConfig{big.NewInt(89), big.NewInt(0), nil, false, big.NewInt(0), common.Hash{}, big.NewInt(0), big.NewInt(0), big.NewInt(0), 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), nil, nil, &CliqueConfig{Period: 0, Epoch: 30000}, nil} AllCliqueProtocolChanges = &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, &CliqueConfig{Period: 0, Epoch: 30000}, nil}
TestXDPoSChanConfig = &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, &XDPoSConfig{Period: 2, Epoch: 900, Reward: 250, RewardCheckpoint: 900, Gap: 890, FoudationWalletAddr: common.HexToAddress("0x0000000000000000000000000000000000000068")}}
// XDPoS config in use for v1 engine only
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, new(EthashConfig), nil, &XDPoSConfig{Epoch: 900, Gap: 450, SkipValidation: true}} 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, new(EthashConfig), nil, &XDPoSConfig{Epoch: 900, Gap: 450, SkipValidation: true}}
TestXDPoSChanConfig = &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, &XDPoSConfig{Period: 2, Epoch: 900, Reward: 250, RewardCheckpoint: 900, Gap: 890, FoudationWalletAddr: common.HexToAddress("0x0000000000000000000000000000000000000068")}} // XDPoS config with v2 engine after block 10
// 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}} TestXDPoSMockChainConfigWithV2Engine = &ChainConfig{big.NewInt(1337), big.NewInt(0), nil, false, big.NewInt(0), common.Hash{}, big.NewInt(0), big.NewInt(0), big.NewInt(0), nil, new(EthashConfig), nil, &XDPoSConfig{Epoch: 900, Gap: 450, SkipValidation: true, V2ConsensusBlockNumber: big.NewInt(10)}}
// 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")}}
TestChainConfig = &ChainConfig{big.NewInt(1), big.NewInt(0), nil, false, big.NewInt(0), common.Hash{}, big.NewInt(0), big.NewInt(0), big.NewInt(0), nil, new(EthashConfig), nil, 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), nil, new(EthashConfig), nil, nil}
TestRules = TestChainConfig.Rules(new(big.Int)) TestRules = TestChainConfig.Rules(new(big.Int))
) )
@ -169,13 +177,14 @@ func (c *CliqueConfig) String() string {
// XDPoSConfig is the consensus engine configs for delegated-proof-of-stake based sealing. // XDPoSConfig is the consensus engine configs for delegated-proof-of-stake based sealing.
type XDPoSConfig struct { type XDPoSConfig struct {
Period uint64 `json:"period"` // Number of seconds between blocks to enforce Period uint64 `json:"period"` // Number of seconds between blocks to enforce
Epoch uint64 `json:"epoch"` // Epoch length to reset votes and checkpoint Epoch uint64 `json:"epoch"` // Epoch length to reset votes and checkpoint
Reward uint64 `json:"reward"` // Block reward - unit Ether Reward uint64 `json:"reward"` // Block reward - unit Ether
RewardCheckpoint uint64 `json:"rewardCheckpoint"` // Checkpoint block for calculate rewards. RewardCheckpoint uint64 `json:"rewardCheckpoint"` // Checkpoint block for calculate rewards.
Gap uint64 `json:"gap"` // Gap time preparing for the next epoch Gap uint64 `json:"gap"` // Gap time preparing for the next epoch
FoudationWalletAddr common.Address `json:"foudationWalletAddr"` // Foundation Address Wallet FoudationWalletAddr common.Address `json:"foudationWalletAddr"` // Foundation Address Wallet
SkipValidation bool //Skip Block Validation for testing purpose SkipValidation bool //Skip Block Validation for testing purpose
V2ConsensusBlockNumber *big.Int
} }
// String implements the stringer interface, returning the consensus engine details. // String implements the stringer interface, returning the consensus engine details.
@ -187,8 +196,11 @@ func (c *XDPoSConfig) String() string {
ConsensusVersion will return the consensus version to use for the provided block number. The returned int represent its version ConsensusVersion will return the consensus version to use for the provided block number. The returned int represent its version
TODO: It's a dummy value for now until the 2.0 consensus engine is fully implemented. TODO: It's a dummy value for now until the 2.0 consensus engine is fully implemented.
*/ */
func BlockConsensusVersion(num *big.Int) int { func (c *XDPoSConfig) BlockConsensusVersion(num *big.Int) string {
return 1 if c.V2ConsensusBlockNumber != nil && num.Cmp(c.V2ConsensusBlockNumber) > 0 {
return ConsensusEngineVersion2
}
return ConsensusEngineVersion1
} }
// String implements the fmt.Stringer interface. // String implements the fmt.Stringer interface.

View file

@ -0,0 +1,46 @@
package consensus
import (
"fmt"
"testing"
"github.com/XinFinOrg/XDPoSChain/consensus/XDPoS"
"github.com/XinFinOrg/XDPoSChain/params"
"github.com/stretchr/testify/assert"
)
func TestAdaptorShouldGetAuthorForDifferentConsensusVersion(t *testing.T) {
blockchain, _, currentBlock := PrepareXDCTestBlockChain(t, 10, params.TestXDPoSMockChainConfigWithV2Engine)
adaptor := blockchain.Engine().(*XDPoS.XDPoS)
addressFromAdaptor, errorAdaptor := adaptor.Author(currentBlock.Header())
if errorAdaptor != nil {
t.Fatalf("Failed while trying to get Author from adaptor")
}
addressFromV1Engine, errV1 := adaptor.EngineV1.Author(currentBlock.Header())
if errV1 != nil {
t.Fatalf("Failed while trying to get Author from engine v1")
}
// Make sure the value is exactly the same as from V1 engine
assert.Equal(t, addressFromAdaptor, addressFromV1Engine)
// Insert one more block to make it above 10, which means now we are on v2 of consensus engine
// Insert block 11
blockCoinBase := fmt.Sprintf("0x111000000000000000000000000000000%03d", 11)
merkleRoot := "35999dded35e8db12de7e6c1471eb9670c162eec616ecebbaf4fddd4676fb930"
block11, err := insertBlock(blockchain, 11, blockCoinBase, currentBlock, merkleRoot)
if err != nil {
t.Fatal(err)
}
addressFromAdaptor, errorAdaptor = adaptor.Author(block11.Header())
if errorAdaptor != nil {
t.Fatalf("Failed while trying to get Author from adaptor")
}
addressFromV2Engine, errV2 := adaptor.EngineV2.Author(block11.Header())
if errV2 != nil {
t.Fatalf("Failed while trying to get Author from engine v2")
}
// Make sure the value is exactly the same as from V2 engine
assert.Equal(t, addressFromAdaptor, addressFromV2Engine)
}

View file

@ -1,368 +1,18 @@
package tests package consensus
import ( import (
"bytes"
"context"
"encoding/hex"
"fmt" "fmt"
"math/big" "math/big"
"reflect" "reflect"
"strings"
"testing" "testing"
"time"
"github.com/XinFinOrg/XDPoSChain/accounts/abi/bind"
"github.com/XinFinOrg/XDPoSChain/accounts/abi/bind/backends"
"github.com/XinFinOrg/XDPoSChain/common"
"github.com/XinFinOrg/XDPoSChain/consensus/XDPoS"
contractValidator "github.com/XinFinOrg/XDPoSChain/contracts/validator/contract"
"github.com/XinFinOrg/XDPoSChain/core"
. "github.com/XinFinOrg/XDPoSChain/core"
"github.com/XinFinOrg/XDPoSChain/core/types" "github.com/XinFinOrg/XDPoSChain/core/types"
"github.com/XinFinOrg/XDPoSChain/core/vm" "github.com/XinFinOrg/XDPoSChain/params"
"github.com/XinFinOrg/XDPoSChain/crypto"
"github.com/XinFinOrg/XDPoSChain/log"
"github.com/XinFinOrg/XDPoSChain/rlp"
) )
type masterNodes map[string]big.Int
type signersList map[string]bool
const GAP = int(450)
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)},
}, 10000000)
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)) // StringToAddress does not exist
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
}, 10000000)
return contractBackend2
}
func transferTx(t *testing.T, to common.Address, transferAmount int64) *types.Transaction {
t.Logf("Transfering %v to address: %v", transferAmount, to.String())
data := []byte{}
gasPrice := big.NewInt(int64(0))
gasLimit := uint64(21000)
amount := big.NewInt(transferAmount)
nonce := uint64(1)
tx := types.NewTransaction(nonce, to, amount, gasLimit, gasPrice, data)
signedTX, err := types.SignTx(tx, types.NewEIP155Signer(big.NewInt(chainID)), voterKey)
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, numOfBlocks int) (*BlockChain, *backends.SimulatedBackend, *types.Block) {
// Preparation
var err error
backend := getCommonBackend(t)
blockchain := backend.GetBlockChain()
blockchain.Client = backend
currentBlock := blockchain.Genesis()
// Insert initial blocks
for i := 1; i <= numOfBlocks; 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
}
// 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,
"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
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,
"0x9319777b782ba2c83a33c995481ff894ac96d9a92a1963091346a3e1e386705c",
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,
ReceiptHash: common.HexToHash(receiptHash),
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)
var gasUsed = new(uint64)
var receipts types.Receipts
for i, tx := range txs {
statedb.Prepare(tx.Hash(), header.Hash(), i)
receipt, _, err, _ := ApplyTransaction(bc.Config(), nil, bc, &header.Coinbase, gp, statedb, nil, &header, tx, gasUsed, vm.Config{})
if err != nil {
return nil, fmt.Errorf("%v when applying transaction", err)
}
receipts = append(receipts, receipt)
}
header.GasUsed = *gasUsed
block = types.NewBlock(&header, txs, nil, receipts)
}
return block, nil
}
// Should NOT update signerList if not on the gap block // Should NOT update signerList if not on the gap block
func TestNotUpdateSignerListIfNotOnGapBlock(t *testing.T) { func TestNotUpdateSignerListIfNotOnGapBlock(t *testing.T) {
blockchain, backend, parentBlock := PrepareXDCTestBlockChain(t, 400) blockchain, backend, parentBlock := PrepareXDCTestBlockChain(t, 400, params.TestXDPoSMockChainConfig)
parentSigners, err := GetSnapshotSigner(blockchain, parentBlock.Header()) parentSigners, err := GetSnapshotSigner(blockchain, parentBlock.Header())
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
@ -400,7 +50,7 @@ func TestNotUpdateSignerListIfNotOnGapBlock(t *testing.T) {
// Should call updateM1 at the gap block, and have the same snapshot values as the parent block if no SM transaction is involved // Should call updateM1 at the gap block, and have the same snapshot values as the parent block if no SM transaction is involved
func TestNotChangeSingerListIfNothingProposedOrVoted(t *testing.T) { func TestNotChangeSingerListIfNothingProposedOrVoted(t *testing.T) {
blockchain, _, parentBlock := PrepareXDCTestBlockChain(t, GAP-1) blockchain, _, parentBlock := PrepareXDCTestBlockChain(t, GAP-1, params.TestXDPoSMockChainConfig)
// Insert block 450 // Insert block 450
blockCoinBase := fmt.Sprintf("0x111000000000000000000000000000000%03d", 450) blockCoinBase := fmt.Sprintf("0x111000000000000000000000000000000%03d", 450)
merkleRoot := "35999dded35e8db12de7e6c1471eb9670c162eec616ecebbaf4fddd4676fb930" merkleRoot := "35999dded35e8db12de7e6c1471eb9670c162eec616ecebbaf4fddd4676fb930"
@ -428,7 +78,7 @@ func TestNotChangeSingerListIfNothingProposedOrVoted(t *testing.T) {
//Should call updateM1 at gap block, and update the snapshot if there are SM transactions involved //Should call updateM1 at gap block, and update the snapshot if there are SM transactions involved
func TestUpdateSignerListIfVotedBeforeGap(t *testing.T) { func TestUpdateSignerListIfVotedBeforeGap(t *testing.T) {
blockchain, backend, parentBlock := PrepareXDCTestBlockChain(t, GAP-2) blockchain, backend, parentBlock := PrepareXDCTestBlockChain(t, GAP-2, params.TestXDPoSMockChainConfig)
// Insert first Block 449 // Insert first Block 449
t.Logf("Inserting block with propose at 449...") t.Logf("Inserting block with propose at 449...")
blockCoinbaseA := "0xaaa0000000000000000000000000000000000449" blockCoinbaseA := "0xaaa0000000000000000000000000000000000449"
@ -469,6 +119,9 @@ func TestUpdateSignerListIfVotedBeforeGap(t *testing.T) {
} }
signers, err = GetSnapshotSigner(blockchain, block450.Header()) signers, err = GetSnapshotSigner(blockchain, block450.Header())
if err != nil {
t.Fatalf("Failed while trying to get signers")
}
// Now, we voted acc 1 to be in the signerList, which will kick out acc3 because it has less funds // Now, we voted acc 1 to be in the signerList, which will kick out acc3 because it has less funds
if signers[acc3Addr.Hex()] == true { if signers[acc3Addr.Hex()] == true {
debugMessage(backend, signers, t) debugMessage(backend, signers, t)
@ -483,7 +136,7 @@ func TestUpdateSignerListIfVotedBeforeGap(t *testing.T) {
//Should call updateM1 before gap block, and update the snapshot if there are SM transactions involved //Should call updateM1 before gap block, and update the snapshot if there are SM transactions involved
func TestCallUpdateM1WithSmartContractTranscation(t *testing.T) { func TestCallUpdateM1WithSmartContractTranscation(t *testing.T) {
blockchain, backend, currentBlock := PrepareXDCTestBlockChain(t, GAP-1) blockchain, backend, currentBlock := PrepareXDCTestBlockChain(t, GAP-1, params.TestXDPoSMockChainConfig)
// Insert first Block 450 A // Insert first Block 450 A
t.Logf("Inserting block with propose at 450 A...") t.Logf("Inserting block with propose at 450 A...")
blockCoinbaseA := "0xaaa0000000000000000000000000000000000450" blockCoinbaseA := "0xaaa0000000000000000000000000000000000450"
@ -512,7 +165,7 @@ func TestCallUpdateM1WithSmartContractTranscation(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) // 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) { func TestCallUpdateM1WhenForkedBlockBackToMainChain(t *testing.T) {
blockchain, backend, currentBlock := PrepareXDCTestBlockChain(t, GAP-1) blockchain, backend, currentBlock := PrepareXDCTestBlockChain(t, GAP-1, params.TestXDPoSMockChainConfig)
// Check initial signer, by default, acc3 is in the signerList // Check initial signer, by default, acc3 is in the signerList
signers, err := GetSnapshotSigner(blockchain, blockchain.CurrentBlock().Header()) signers, err := GetSnapshotSigner(blockchain, blockchain.CurrentBlock().Header())
if err != nil { if err != nil {
@ -635,9 +288,12 @@ func TestCallUpdateM1WhenForkedBlockBackToMainChain(t *testing.T) {
func TestStatesShouldBeUpdatedWhenForkedBlockBecameMainChainAtGapBlock(t *testing.T) { func TestStatesShouldBeUpdatedWhenForkedBlockBecameMainChainAtGapBlock(t *testing.T) {
blockchain, backend, parentBlock := PrepareXDCTestBlockChain(t, GAP-1) blockchain, backend, parentBlock := PrepareXDCTestBlockChain(t, GAP-1, params.TestXDPoSMockChainConfig)
state, err := blockchain.State() state, err := blockchain.State()
if err != nil {
t.Fatalf("Failed while trying to get blockchain state")
}
t.Logf("Account %v have balance of: %v", acc1Addr.String(), state.GetBalance(acc1Addr)) t.Logf("Account %v have balance of: %v", acc1Addr.String(), state.GetBalance(acc1Addr))
// Check initial signer // Check initial signer
signers, err := GetSnapshotSigner(blockchain, blockchain.CurrentBlock().Header()) signers, err := GetSnapshotSigner(blockchain, blockchain.CurrentBlock().Header())
@ -665,6 +321,9 @@ func TestStatesShouldBeUpdatedWhenForkedBlockBecameMainChainAtGapBlock(t *testin
t.Fatal(err) t.Fatal(err)
} }
state, err = blockchain.State() state, err = blockchain.State()
if err != nil {
t.Fatalf("Failed while trying to get blockchain state")
}
t.Log("After transfer transaction at block 450 A, Account 1 have balance of: ", state.GetBalance(acc1Addr)) t.Log("After transfer transaction at block 450 A, Account 1 have balance of: ", state.GetBalance(acc1Addr))
if state.GetBalance(acc1Addr).Cmp(new(big.Int).SetUint64(10000000999)) != 0 { if state.GetBalance(acc1Addr).Cmp(new(big.Int).SetUint64(10000000999)) != 0 {
@ -697,6 +356,9 @@ func TestStatesShouldBeUpdatedWhenForkedBlockBecameMainChainAtGapBlock(t *testin
t.Fatal(err) t.Fatal(err)
} }
state, err = blockchain.State() state, err = blockchain.State()
if err != nil {
t.Fatalf("Failed while trying to get blockchain state")
}
if state.GetBalance(acc1Addr).Cmp(new(big.Int).SetUint64(10000000999)) != 0 { if state.GetBalance(acc1Addr).Cmp(new(big.Int).SetUint64(10000000999)) != 0 {
t.Fatalf("account 1 should have 10000000999 in balance as the block is forked, not on the main chain") t.Fatalf("account 1 should have 10000000999 in balance as the block is forked, not on the main chain")
} }
@ -749,6 +411,9 @@ func TestStatesShouldBeUpdatedWhenForkedBlockBecameMainChainAtGapBlock(t *testin
t.Fatalf("acc2Addr should sit in the signer list") t.Fatalf("acc2Addr should sit in the signer list")
} }
state, err = blockchain.State() state, err = blockchain.State()
if err != nil {
t.Fatalf("Failed while trying to get blockchain state")
}
t.Log("After transfer transaction at block 450 B and the B fork has been merged into main chain, Account 1 have balance of: ", state.GetBalance(acc1Addr)) t.Log("After transfer transaction at block 450 B and the B fork has been merged into main chain, Account 1 have balance of: ", state.GetBalance(acc1Addr))
if state.GetBalance(acc1Addr).Cmp(new(big.Int).SetUint64(10000000888)) != 0 { if state.GetBalance(acc1Addr).Cmp(new(big.Int).SetUint64(10000000888)) != 0 {
@ -757,7 +422,7 @@ func TestStatesShouldBeUpdatedWhenForkedBlockBecameMainChainAtGapBlock(t *testin
} }
func TestVoteShouldNotBeAffectedByFork(t *testing.T) { func TestVoteShouldNotBeAffectedByFork(t *testing.T) {
blockchain, backend, parentBlock := PrepareXDCTestBlockChain(t, GAP-1) blockchain, backend, parentBlock := PrepareXDCTestBlockChain(t, GAP-1, params.TestXDPoSMockChainConfig)
// Check initial signer, by default, acc3 is in the signerList // Check initial signer, by default, acc3 is in the signerList
signers, err := GetSnapshotSigner(blockchain, blockchain.CurrentBlock().Header()) signers, err := GetSnapshotSigner(blockchain, blockchain.CurrentBlock().Header())
if err != nil { if err != nil {

View file

@ -0,0 +1,367 @@
package consensus
import (
"bytes"
"context"
"encoding/hex"
"fmt"
"math/big"
"strings"
"testing"
"time"
"github.com/XinFinOrg/XDPoSChain/accounts/abi/bind"
"github.com/XinFinOrg/XDPoSChain/accounts/abi/bind/backends"
"github.com/XinFinOrg/XDPoSChain/common"
"github.com/XinFinOrg/XDPoSChain/consensus/XDPoS"
contractValidator "github.com/XinFinOrg/XDPoSChain/contracts/validator/contract"
"github.com/XinFinOrg/XDPoSChain/core"
. "github.com/XinFinOrg/XDPoSChain/core"
"github.com/XinFinOrg/XDPoSChain/core/types"
"github.com/XinFinOrg/XDPoSChain/core/vm"
"github.com/XinFinOrg/XDPoSChain/crypto"
"github.com/XinFinOrg/XDPoSChain/log"
"github.com/XinFinOrg/XDPoSChain/params"
"github.com/XinFinOrg/XDPoSChain/rlp"
)
type masterNodes map[string]big.Int
type signersList map[string]bool
const GAP = int(450)
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, chainConfig *params.ChainConfig) *backends.SimulatedBackend {
// initial helper backend
contractBackendForSC := backends.NewXDCSimulatedBackend(core.GenesisAlloc{
voterAddr: {Balance: new(big.Int).SetUint64(10000000000)},
}, 10000000, chainConfig)
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)) // StringToAddress does not exist
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")
err := rlp.DecodeBytes(trim, &decode)
if err != nil {
t.Fatalf("Failed while decode byte")
}
storage[key] = common.BytesToHash(decode)
log.Info("DecodeBytes", "value", val.String(), "decode", storage[key].String())
return true
}
err = contractBackendForSC.ForEachStorageAt(ctx, validatorSCAddr, nil, f)
if err != nil {
t.Fatalf("Failed while trying to read all keys from SC")
}
// 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
}, 10000000, chainConfig)
return contractBackend2
}
func transferTx(t *testing.T, to common.Address, transferAmount int64) *types.Transaction {
t.Logf("Transfering %v to address: %v", transferAmount, to.String())
data := []byte{}
gasPrice := big.NewInt(int64(0))
gasLimit := uint64(21000)
amount := big.NewInt(transferAmount)
nonce := uint64(1)
tx := types.NewTransaction(nonce, to, amount, gasLimit, gasPrice, data)
signedTX, err := types.SignTx(tx, types.NewEIP155Signer(big.NewInt(chainID)), voterKey)
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, numOfBlocks int, chainConfig *params.ChainConfig) (*BlockChain, *backends.SimulatedBackend, *types.Block) {
// Preparation
var err error
backend := getCommonBackend(t, chainConfig)
blockchain := backend.GetBlockChain()
blockchain.Client = backend
currentBlock := blockchain.Genesis()
// Insert initial blocks
for i := 1; i <= numOfBlocks; 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
}
// 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,
"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
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,
"0x9319777b782ba2c83a33c995481ff894ac96d9a92a1963091346a3e1e386705c",
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,
ReceiptHash: common.HexToHash(receiptHash),
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)
var gasUsed = new(uint64)
var receipts types.Receipts
for i, tx := range txs {
statedb.Prepare(tx.Hash(), header.Hash(), i)
receipt, _, err, _ := ApplyTransaction(bc.Config(), nil, bc, &header.Coinbase, gp, statedb, nil, &header, tx, gasUsed, vm.Config{})
if err != nil {
return nil, fmt.Errorf("%v when applying transaction", err)
}
receipts = append(receipts, receipt)
}
header.GasUsed = *gasUsed
block = types.NewBlock(&header, txs, nil, receipts)
}
return block, nil
}
// /*
// 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
// }
// */