diff --git a/.travis.yml b/.travis.yml index 638418c06c..9b86db97b6 100644 --- a/.travis.yml +++ b/.travis.yml @@ -13,39 +13,80 @@ jobs: - stage: Lint sudo: false - go: '1.12.x' + go: '1.14.x' git: submodules: false script: - go run build/ci.go lint - - stage: Build and test - go: '1.12.x' - script: - - sudo modprobe fuse - - sudo chmod 666 /dev/fuse - - sudo chown root:$USER /etc/fuse.conf - - go run build/ci.go install - - while sleep 540; do echo "[ still running ]"; done & - - go run build/ci.go test -coverage - - kill %1 - after_success: - - bash <(curl -s https://codecov.io/bash) - - - go: '1.11.x' - script: - - sudo modprobe fuse - - sudo chmod 666 /dev/fuse - - sudo chown root:$USER /etc/fuse.conf - - go run build/ci.go install - - while sleep 540; do echo "[ still running ]"; done & - - go run build/ci.go test -coverage - - kill %1 - + - stage: Tests + os: linux + dist: bionic + go: 1.14.x + env: + - GO111MODULE=auto + name: A-B tests + script: travis_retry go run build/ci.go test -coverage $(go list ./... | grep "github.com\/XinFinOrg\/XDPoSChain\/[a-b].*") + - script: travis_retry go run build/ci.go test -coverage $(go list ./... | grep "github.com\/XinFinOrg\/XDPoSChain\/c[a-m].*") + os: linux + dist: bionic + go: 1.14.x + env: + - GO111MODULE=auto + name: C-[a-m] tests + - script: travis_retry go run build/ci.go test -coverage $(go list ./... | grep "github.com\/XinFinOrg\/XDPoSChain\/c[n-o].*") + os: linux + dist: bionic + go: 1.14.x + env: + - GO111MODULE=auto + name: C-[n-o] tests + - script: travis_retry go run build/ci.go test -coverage $(go list ./... | grep "github.com\/XinFinOrg\/XDPoSChain\/c[p-z].*") + os: linux + dist: bionic + go: 1.14.x + env: + - GO111MODULE=auto + name: C-[p-z] tests + - script: travis_retry go run build/ci.go test -coverage $(go list ./... | grep "github.com\/XinFinOrg\/XDPoSChain\/[d-i].*") + os: linux + dist: bionic + go: 1.14.x + env: + - GO111MODULE=auto + name: D-I tests + - script: travis_retry go run build/ci.go test -coverage $(go list ./... | grep "github.com\/XinFinOrg\/XDPoSChain\/[j-n].*") + os: linux + dist: bionic + go: 1.14.x + env: + - GO111MODULE=auto + name: J-N tests + - script: travis_retry go run build/ci.go test -coverage $(go list ./... | grep "github.com\/XinFinOrg\/XDPoSChain\/[o-r].*") + os: linux + dist: bionic + go: 1.14.x + env: + - GO111MODULE=auto + name: O-R tests + - script: travis_retry go run build/ci.go test -coverage $(go list ./... | grep "github.com\/XinFinOrg\/XDPoSChain\/s.*") + os: linux + dist: bionic + go: 1.14.x + env: + - GO111MODULE=auto + name: S tests + - script: travis_retry go run build/ci.go test -coverage $(go list ./... | grep "github.com\/XinFinOrg\/XDPoSChain\/[t-z].*") + os: linux + dist: bionic + go: 1.14.x + env: + - GO111MODULE=auto + name: T-Z tests - stage: Github release - go: '1.12.x' + go: '1.14.x' script: - - GOARCH=amd64 GOOS=linux go build -o ./build/bin/XDC-linux-amd64 -v ./cmd/XDC + - GOARCH=amd64 GOOS=linux go build -o ./build/bin/XDC-linux-amd64 ./cmd/XDC deploy: provider: releases api_key: $GITHUB_TOKEN @@ -61,46 +102,46 @@ jobs: - docker install: skip before_script: - - docker build -t XDPoSChain/XDPoSChain . - - docker build -t XDPoSChain/node -f Dockerfile.node . + - docker build -t XinFinOrg/XDPoSChain . + - docker build -t XinFinOrg/node -f Dockerfile.node . script: - echo "$DOCKER_PASSWORD" | docker login --username "$DOCKER_USERNAME" --password-stdin - - docker tag XDPoSChain/XDPoSChain XDPoSChain/XDPoSChain:latest - - docker push XDPoSChain/XDPoSChain:latest - - docker tag XDPoSChain/XDPoSChain XDPoSChain/XDPoSChain:$TRAVIS_BUILD_ID - - docker push XDPoSChain/XDPoSChain:$TRAVIS_BUILD_ID - - docker tag XDPoSChain/node XDPoSChain/node:latest - - docker push XDPoSChain/node:latest - - docker tag XDPoSChain/node XDPoSChain/node:$TRAVIS_BUILD_ID - - docker push XDPoSChain/node:$TRAVIS_BUILD_ID + - docker tag XinFinOrg/XDPoSChain XinFinOrg/XDPoSChain:latest + - docker push XinFinOrg/XDPoSChain:latest + - docker tag XinFinOrg/XDPoSChain XinFinOrg/XDPoSChain:$TRAVIS_BUILD_ID + - docker push XinFinOrg/XDPoSChain:$TRAVIS_BUILD_ID + - docker tag XinFinOrg/node XinFinOrg/node:latest + - docker push XinFinOrg/node:latest + - docker tag XinFinOrg/node XinFinOrg/node:$TRAVIS_BUILD_ID + - docker push XinFinOrg/node:$TRAVIS_BUILD_ID - stage: Build and push image (tagged) services: - docker install: skip before_script: - - docker build -t XDPoSChain/XDPoSChain . - - docker build -t XDPoSChain/XDPoSChain -f Dockerfile.node . + - docker build -t XinFinOrg/XDPoSChain . + - docker build -t XinFinOrg/XDPoSChain -f Dockerfile.node . script: - echo "$DOCKER_PASSWORD" | docker login --username "$DOCKER_USERNAME" --password-stdin - - docker tag XDPoSChain/XDPoSChain XDPoSChain/XDPoSChain:latest - - docker push XDPoSChain/XDPoSChain:latest - - docker tag XDPoSChain/XDPoSChain XDPoSChain/XDPoSChain:$TRAVIS_TAG - - docker push XDPoSChain/XDPoSChain:$TRAVIS_TAG - - docker tag XDPoSChain/XDPoSChain XDPoSChain/node:latest - - docker push XDPoSChain/node:latest - - docker tag XDPoSChain/node XDPoSChain/node:$TRAVIS_TAG - - docker push XDPoSChain/node:$TRAVIS_TAG + - docker tag XinFinOrg/XDPoSChain XinFinOrg/XDPoSChain:latest + - docker push XinFinOrg/XDPoSChain:latest + - docker tag XinFinOrg/XDPoSChain XinFinOrg/XDPoSChain:$TRAVIS_TAG + - docker push XinFinOrg/XDPoSChain:$TRAVIS_TAG + - docker tag XinFinOrg/XDPoSChain XinFinOrg/node:latest + - docker push XinFinOrg/node:latest + - docker tag XinFinOrg/node XinFinOrg/node:$TRAVIS_TAG + - docker push XinFinOrg/node:$TRAVIS_TAG stages: - name: Lint - name: Build and test - name: Github release - if: type != pull_request AND branch =~ ^v AND tag IS present AND repo = XDPoSChain/XDPoSChain + if: type != pull_request AND branch =~ ^v AND tag IS present AND repo = XinFinOrg/XDPoSChain - name: Build and push image - if: type != pull_request AND branch = master AND tag IS blank AND repo = XDPoSChain/XDPoSChain + if: type != pull_request AND branch = master AND tag IS blank AND repo = XinFinOrg/XDPoSChain - name: Build and push image (tagged) - if: type != pull_request AND branch =~ ^v AND tag IS present AND repo = XDPoSChain/XDPoSChain + if: type != pull_request AND branch =~ ^v AND tag IS present AND repo = XinFinOrg/XDPoSChain notifications: slack: diff --git a/accounts/abi/bind/backends/simulated.go b/accounts/abi/bind/backends/simulated.go index ca5972e32d..1f0f98e3b3 100644 --- a/accounts/abi/bind/backends/simulated.go +++ b/accounts/abi/bind/backends/simulated.go @@ -20,16 +20,18 @@ import ( "context" "errors" "fmt" - "github.com/XinFinOrg/XDPoSChain/consensus" - "github.com/XinFinOrg/XDPoSChain/core/rawdb" "math/big" "sync" "time" + "github.com/XinFinOrg/XDPoSChain/consensus" + "github.com/XinFinOrg/XDPoSChain/core/rawdb" + "github.com/XinFinOrg/XDPoSChain" "github.com/XinFinOrg/XDPoSChain/accounts/abi/bind" "github.com/XinFinOrg/XDPoSChain/common" "github.com/XinFinOrg/XDPoSChain/common/math" + "github.com/XinFinOrg/XDPoSChain/consensus/XDPoS" "github.com/XinFinOrg/XDPoSChain/consensus/ethash" "github.com/XinFinOrg/XDPoSChain/core" "github.com/XinFinOrg/XDPoSChain/core/bloombits" @@ -64,6 +66,31 @@ type SimulatedBackend struct { config *params.ChainConfig } +// XDC simulated backend for testing purpose. +func NewXDCSimulatedBackend(alloc core.GenesisAlloc, gasLimit uint64) *SimulatedBackend { + // database := ethdb.NewMemDatabase() + database := rawdb.NewMemoryDatabase() + + genesis := core.Genesis{ + GasLimit: gasLimit, // need this big, support initial smart contract + Config: params.TestXDPoSMockChainConfig, + Alloc: alloc, + ExtraData: append(make([]byte, 32), make([]byte, 65)...), + } + genesis.MustCommit(database) + blockchain, _ := core.NewBlockChain(database, nil, genesis.Config, XDPoS.NewFaker(database), vm.Config{}) + + backend := &SimulatedBackend{ + database: database, + blockchain: blockchain, + config: genesis.Config, + events: filters.NewEventSystem(new(event.TypeMux), &filterBackend{database, blockchain}, false), + } + blockchain.Client = backend + backend.rollback() + return backend +} + // NewSimulatedBackend creates a new binding backend using a simulated blockchain // for testing purposes. func NewSimulatedBackend(alloc core.GenesisAlloc) *SimulatedBackend { @@ -103,7 +130,7 @@ func (b *SimulatedBackend) Rollback() { } func (b *SimulatedBackend) rollback() { - blocks, _ := core.GenerateChain(b.config, b.blockchain.CurrentBlock(), ethash.NewFaker(), b.database, 1, func(int, *core.BlockGen) {}) + blocks, _ := core.GenerateChain(b.config, b.blockchain.CurrentBlock(), b.blockchain.Engine(), b.database, 1, func(int, *core.BlockGen) {}) statedb, _ := b.blockchain.State() b.pendingBlock = blocks[0] @@ -359,7 +386,8 @@ func (b *SimulatedBackend) SendTransaction(ctx context.Context, tx *types.Transa panic(fmt.Errorf("invalid transaction nonce: got %d, want %d", tx.Nonce(), nonce)) } - blocks, _ := core.GenerateChain(b.config, b.blockchain.CurrentBlock(), ethash.NewFaker(), b.database, 1, func(number int, block *core.BlockGen) { + blocks, _ := core.GenerateChain(b.config, b.blockchain.CurrentBlock(), b.blockchain.Engine(), b.database, 1, func(number int, block *core.BlockGen) { + // blocks, _ := core.GenerateChain(b.config, b.blockchain.CurrentBlock(), b.blockchain.Engine(), b.database, 1, func(number int, block *core.BlockGen) { for _, tx := range b.pendingBlock.Transactions() { block.AddTxWithChain(b.blockchain, tx) } @@ -438,7 +466,8 @@ func (b *SimulatedBackend) SubscribeFilterLogs(ctx context.Context, query XDPoSC func (b *SimulatedBackend) AdjustTime(adjustment time.Duration) error { b.mu.Lock() defer b.mu.Unlock() - blocks, _ := core.GenerateChain(b.config, b.blockchain.CurrentBlock(), ethash.NewFaker(), b.database, 1, func(number int, block *core.BlockGen) { + blocks, _ := core.GenerateChain(b.config, b.blockchain.CurrentBlock(), b.blockchain.Engine(), b.database, 1, func(number int, block *core.BlockGen) { + // blocks, _ := core.GenerateChain(b.config, b.blockchain.CurrentBlock(), b.blockchain.Engine(), b.database, 1, func(number int, block *core.BlockGen) { for _, tx := range b.pendingBlock.Transactions() { block.AddTx(tx) } @@ -452,6 +481,10 @@ func (b *SimulatedBackend) AdjustTime(adjustment time.Duration) error { return nil } +func (b *SimulatedBackend) GetBlockChain() *core.BlockChain { + return b.blockchain +} + // callmsg implements core.Message to allow passing it as a transaction simulator. type callmsg struct { XDPoSChain.CallMsg diff --git a/accounts/abi/bind/bind_test.go b/accounts/abi/bind/bind_test.go index 242cea0ef6..858a2a0cc9 100644 --- a/accounts/abi/bind/bind_test.go +++ b/accounts/abi/bind/bind_test.go @@ -229,7 +229,7 @@ var bindTests = []struct { // Generate a new random account and a funded simulator key, _ := crypto.GenerateKey() auth := bind.NewKeyedTransactor(key) - sim := backends.NewSimulatedBackend(core.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000)}}) + sim := backends.NewXDCSimulatedBackend(core.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000)}}, 10000000) // Deploy an interaction tester contract and call a transaction on it _, _, interactor, err := DeployInteractor(auth, sim, "Deploy string") @@ -270,7 +270,7 @@ var bindTests = []struct { // Generate a new random account and a funded simulator key, _ := crypto.GenerateKey() auth := bind.NewKeyedTransactor(key) - sim := backends.NewSimulatedBackend(core.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000)}}) + sim := backends.NewXDCSimulatedBackend(core.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000)}}, 10000000) // Deploy a tuple tester contract and execute a structured call on it _, _, getter, err := DeployGetter(auth, sim) @@ -302,7 +302,7 @@ var bindTests = []struct { // Generate a new random account and a funded simulator key, _ := crypto.GenerateKey() auth := bind.NewKeyedTransactor(key) - sim := backends.NewSimulatedBackend(core.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000)}}) + sim := backends.NewXDCSimulatedBackend(core.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000)}}, 10000000) // Deploy a tuple tester contract and execute a structured call on it _, _, tupler, err := DeployTupler(auth, sim) @@ -344,7 +344,7 @@ var bindTests = []struct { // Generate a new random account and a funded simulator key, _ := crypto.GenerateKey() auth := bind.NewKeyedTransactor(key) - sim := backends.NewSimulatedBackend(core.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000)}}) + sim := backends.NewXDCSimulatedBackend(core.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000)}}, 10000000) // Deploy a slice tester contract and execute a n array call on it _, _, slicer, err := DeploySlicer(auth, sim) @@ -378,7 +378,7 @@ var bindTests = []struct { // Generate a new random account and a funded simulator key, _ := crypto.GenerateKey() auth := bind.NewKeyedTransactor(key) - sim := backends.NewSimulatedBackend(core.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000)}}) + sim := backends.NewXDCSimulatedBackend(core.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000)}}, 10000000) // Deploy a default method invoker contract and execute its default method _, _, defaulter, err := DeployDefaulter(auth, sim) @@ -411,7 +411,7 @@ var bindTests = []struct { `[{"constant":true,"inputs":[],"name":"String","outputs":[{"name":"","type":"string"}],"type":"function"}]`, ` // Create a simulator and wrap a non-deployed contract - sim := backends.NewSimulatedBackend(nil) + sim := backends.NewXDCSimulatedBackend(nil, uint64(10000000000)) nonexistent, err := NewNonExistent(common.Address{}, sim) if err != nil { @@ -447,7 +447,7 @@ var bindTests = []struct { // Generate a new random account and a funded simulator key, _ := crypto.GenerateKey() auth := bind.NewKeyedTransactor(key) - sim := backends.NewSimulatedBackend(core.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000)}}) + sim := backends.NewXDCSimulatedBackend(core.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000)}}, 10000000) // Deploy a funky gas pattern contract _, _, limiter, err := DeployFunkyGasPattern(auth, sim) @@ -482,7 +482,7 @@ var bindTests = []struct { // Generate a new random account and a funded simulator key, _ := crypto.GenerateKey() auth := bind.NewKeyedTransactor(key) - sim := backends.NewSimulatedBackend(core.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000)}}) + sim := backends.NewXDCSimulatedBackend(core.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000)}}, 10000000) // Deploy a sender tester contract and execute a structured call on it _, _, callfrom, err := DeployCallFrom(auth, sim) @@ -542,7 +542,7 @@ var bindTests = []struct { // Generate a new random account and a funded simulator key, _ := crypto.GenerateKey() auth := bind.NewKeyedTransactor(key) - sim := backends.NewSimulatedBackend(core.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000)}}) + sim := backends.NewXDCSimulatedBackend(core.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000)}}, 10000000) // Deploy a underscorer tester contract and execute a structured call on it _, _, underscorer, err := DeployUnderscorer(auth, sim) @@ -612,7 +612,7 @@ var bindTests = []struct { // Generate a new random account and a funded simulator key, _ := crypto.GenerateKey() auth := bind.NewKeyedTransactor(key) - sim := backends.NewSimulatedBackend(core.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000)}}) + sim := backends.NewXDCSimulatedBackend(core.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000)}}, 10000000) // Deploy an eventer contract _, _, eventer, err := DeployEventer(auth, sim) @@ -761,7 +761,7 @@ var bindTests = []struct { // Generate a new random account and a funded simulator key, _ := crypto.GenerateKey() auth := bind.NewKeyedTransactor(key) - sim := backends.NewSimulatedBackend(core.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000)}}) + sim := backends.NewXDCSimulatedBackend(core.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000)}}, 10000000) //deploy the test contract _, _, testContract, err := DeployDeeplyNestedArray(auth, sim) diff --git a/accounts/abi/bind/util_test.go b/accounts/abi/bind/util_test.go index a983f02e00..306fc7b3ca 100644 --- a/accounts/abi/bind/util_test.go +++ b/accounts/abi/bind/util_test.go @@ -53,9 +53,11 @@ var waitDeployedTests = map[string]struct { func TestWaitDeployed(t *testing.T) { for name, test := range waitDeployedTests { - backend := backends.NewSimulatedBackend(core.GenesisAlloc{ - crypto.PubkeyToAddress(testKey.PublicKey): {Balance: big.NewInt(10000000000)}, - }) + backend := backends.NewXDCSimulatedBackend( + core.GenesisAlloc{ + crypto.PubkeyToAddress(testKey.PublicKey): {Balance: big.NewInt(10000000000)}, + }, 10000000, + ) // Create the transaction. tx := types.NewContractCreation(0, big.NewInt(0), test.gas, big.NewInt(1), common.FromHex(test.code)) diff --git a/accounts/keystore/testdata/keystore/README b/accounts/keystore/testdata/keystore/README index a5a86f964d..c489123c26 100644 --- a/accounts/keystore/testdata/keystore/README +++ b/accounts/keystore/testdata/keystore/README @@ -4,11 +4,11 @@ The passphrase that unlocks them is "foobar". The "good" key files which are supposed to be loadable are: - File: UTC--2016-03-22T12-57-55.920751759Z--7ef5a6135f1fd6a02593eedc869c6d41d934aef8 - Address: 0x7ef5a6135f1fd6a02593eedc869c6d41d934aef8 + Address: xdc7ef5a6135f1fd6a02593eedc869c6d41d934aef8 - File: aaa - Address: 0xf466859ead1932d743d622cb74fc058882e8648a + Address: xdcf466859ead1932d743d622cb74fc058882e8648a - File: zzz - Address: 0x289d485d9771714cce91d3393d764e1311907acc + Address: xdc289d485d9771714cce91d3393d764e1311907acc The other files (including this README) are broken in various ways and should not be picked up by package accounts: diff --git a/cmd/XDC/accountcmd_test.go b/cmd/XDC/accountcmd_test.go index 78f0ab3321..04553b1356 100644 --- a/cmd/XDC/accountcmd_test.go +++ b/cmd/XDC/accountcmd_test.go @@ -75,7 +75,7 @@ Your new account is locked with a password. Please give a password. Do not forge Passphrase: {{.InputLine "foobar"}} Repeat passphrase: {{.InputLine "foobar"}} `) - XDC.ExpectRegexp(`Address: \{[0-9a-f]{40}\}\n`) + XDC.ExpectRegexp(`Address: \{xdc[0-9a-f]{40}\}\n`) } func TestAccountNewBadRepeat(t *testing.T) { @@ -112,7 +112,7 @@ func TestWalletImport(t *testing.T) { XDC.Expect(` !! Unsupported terminal, password will be echoed. Passphrase: {{.InputLine "foo"}} -Address: {d4584b5f6229b7be90727b0fc8c6b91bb427821f} +Address: {xdcd4584b5f6229b7be90727b0fc8c6b91bb427821f} `) files, err := ioutil.ReadDir(filepath.Join(XDC.Datadir, "keystore")) @@ -146,7 +146,7 @@ Passphrase: {{.InputLine "foobar"}} wantMessages := []string{ "Unlocked account", - "=0xf466859eAD1932D743d622CB74FC058882E8648A", + "=xdcf466859eAD1932D743d622CB74FC058882E8648A", } for _, m := range wantMessages { if !strings.Contains(XDC.StderrText(), m) { @@ -191,8 +191,8 @@ Passphrase: {{.InputLine "foobar"}} wantMessages := []string{ "Unlocked account", - "=0x7EF5A6135f1FD6a02593eEdC869c6D41D934aef8", - "=0x289d485D9771714CCe91D3393D764E1311907ACc", + "=xdc7EF5A6135f1FD6a02593eEdC869c6D41D934aef8", + "=xdc289d485D9771714CCe91D3393D764E1311907ACc", } for _, m := range wantMessages { if !strings.Contains(XDC.StderrText(), m) { @@ -211,8 +211,8 @@ func TestUnlockFlagPasswordFile(t *testing.T) { wantMessages := []string{ "Unlocked account", - "=0x7EF5A6135f1FD6a02593eEdC869c6D41D934aef8", - "=0x289d485D9771714CCe91D3393D764E1311907ACc", + "=xdc7EF5A6135f1FD6a02593eEdC869c6D41D934aef8", + "=xdc289d485D9771714CCe91D3393D764E1311907ACc", } for _, m := range wantMessages { if !strings.Contains(XDC.StderrText(), m) { @@ -261,7 +261,7 @@ In order to avoid this warning, you need to remove the following duplicate key f wantMessages := []string{ "Unlocked account", - "=0xf466859eAD1932D743d622CB74FC058882E8648A", + "=xdcf466859eAD1932D743d622CB74FC058882E8648A", } for _, m := range wantMessages { if !strings.Contains(XDC.StderrText(), m) { diff --git a/cmd/XDC/consolecmd_test.go b/cmd/XDC/consolecmd_test.go index 879577df0f..2801583ce2 100644 --- a/cmd/XDC/consolecmd_test.go +++ b/cmd/XDC/consolecmd_test.go @@ -31,14 +31,14 @@ import ( ) const ( - ipcAPIs = "admin:1.0 debug:1.0 eth:1.0 miner:1.0 net:1.0 personal:1.0 XDPoS:1.0 rpc:1.0 XDCx:1.0 XDCxlending:1.0 txpool:1.0 web3:1.0" + ipcAPIs = "XDCx:1.0 XDCxlending:1.0 XDPoS:1.0 admin:1.0 debug:1.0 eth:1.0 miner:1.0 net:1.0 personal:1.0 rpc:1.0 txpool:1.0 web3:1.0" httpAPIs = "eth:1.0 net:1.0 rpc:1.0 web3:1.0" ) // Tests that a node embedded within a console can be started up properly and // then terminated by closing the input stream. func TestConsoleWelcome(t *testing.T) { - coinbase := "0x8605cdbbdb6d264aa742e77020dcbc58fcdce182" + coinbase := "xdc8605cdbbdb6d264aa742e77020dcbc58fcdce182" // Start a XDC console, make sure it's cleaned up and terminate the console XDC := runXDC(t, @@ -73,7 +73,7 @@ at block: 0 ({{niltime}}) // Tests that a console can be attached to a running node via various means. func TestIPCAttachWelcome(t *testing.T) { // Configure the instance for IPC attachement - coinbase := "0x8605cdbbdb6d264aa742e77020dcbc58fcdce182" + coinbase := "xdc8605cdbbdb6d264aa742e77020dcbc58fcdce182" var ipc string if runtime.GOOS == "windows" { ipc = `\\.\pipe\XDC` + strconv.Itoa(trulyRandInt(100000, 999999)) @@ -95,7 +95,7 @@ func TestIPCAttachWelcome(t *testing.T) { } func TestHTTPAttachWelcome(t *testing.T) { - coinbase := "0x8605cdbbdb6d264aa742e77020dcbc58fcdce182" + coinbase := "xdc8605cdbbdb6d264aa742e77020dcbc58fcdce182" port := strconv.Itoa(trulyRandInt(1024, 65536)) // Yeah, sometimes this will fail, sorry :P XDC := runXDC(t, "--XDCx.datadir", tmpdir(t)+"XDCx/"+time.Now().String(), @@ -110,7 +110,7 @@ func TestHTTPAttachWelcome(t *testing.T) { } func TestWSAttachWelcome(t *testing.T) { - coinbase := "0x8605cdbbdb6d264aa742e77020dcbc58fcdce182" + coinbase := "xdc8605cdbbdb6d264aa742e77020dcbc58fcdce182" port := strconv.Itoa(trulyRandInt(1024, 65536)) // Yeah, sometimes this will fail, sorry :P XDC := runXDC(t, diff --git a/cmd/ethkey/message_test.go b/cmd/ethkey/message_test.go index 39352b1d22..e8e3806654 100644 --- a/cmd/ethkey/message_test.go +++ b/cmd/ethkey/message_test.go @@ -40,7 +40,7 @@ func TestMessageSignVerify(t *testing.T) { Passphrase: {{.InputLine "foobar"}} Repeat passphrase: {{.InputLine "foobar"}} `) - _, matches := generate.ExpectRegexp(`Address: (0x[0-9a-fA-F]{40})\n`) + _, matches := generate.ExpectRegexp(`Address: (xdc[0-9a-fA-F]{40})\n`) address := matches[1] generate.ExpectExit() @@ -59,7 +59,7 @@ Passphrase: {{.InputLine "foobar"}} _, matches = verify.ExpectRegexp(` Signature verification successful! Recovered public key: [0-9a-f]+ -Recovered address: (0x[0-9a-fA-F]{40}) +Recovered address: (xdc[0-9a-fA-F]{40}) `) recovered := matches[1] verify.ExpectExit() diff --git a/cmd/puppeth/wizard_genesis.go b/cmd/puppeth/wizard_genesis.go index 9c036c9873..2a04ba5946 100644 --- a/cmd/puppeth/wizard_genesis.go +++ b/cmd/puppeth/wizard_genesis.go @@ -177,7 +177,7 @@ func (w *wizard) makeGenesis() { // Validator Smart Contract Code pKey, _ := crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") addr := crypto.PubkeyToAddress(pKey.PublicKey) - contractBackend := backends.NewSimulatedBackend(core.GenesisAlloc{addr: {Balance: big.NewInt(1000000000)}}) + contractBackend := backends.NewXDCSimulatedBackend(core.GenesisAlloc{addr: {Balance: big.NewInt(1000000000)}}, 10000000) transactOpts := bind.NewKeyedTransactor(pKey) validatorAddress, _, err := validatorContract.DeployValidator(transactOpts, contractBackend, signers, validatorCaps, owner) diff --git a/common/types.go b/common/types.go index 7e0b5f2587..4c31429a53 100644 --- a/common/types.go +++ b/common/types.go @@ -167,9 +167,16 @@ func BytesToAddress(b []byte) Address { a.SetBytes(b) return a } + func StringToAddress(s string) Address { return BytesToAddress([]byte(s)) } -func BigToAddress(b *big.Int) Address { return BytesToAddress(b.Bytes()) } -func HexToAddress(s string) Address { return BytesToAddress(FromHex(s)) } + +// BigToAddress returns Address with byte values of b. +// If b is larger than len(h), b will be cropped from the left. +func BigToAddress(b *big.Int) Address { return BytesToAddress(b.Bytes()) } + +// HexToAddress returns Address with byte values of s. +// If s is larger than len(h), s will be cropped from the left. +func HexToAddress(s string) Address { return BytesToAddress(FromHex(s)) } // IsHexAddress verifies whether a string can represent a valid hex-encoded // Ethereum address or not. diff --git a/consensus/XDPoS/XDPoS.go b/consensus/XDPoS/XDPoS.go index b54902a6a1..d4b19bba84 100644 --- a/consensus/XDPoS/XDPoS.go +++ b/consensus/XDPoS/XDPoS.go @@ -297,6 +297,32 @@ func New(config *params.XDPoSConfig, db ethdb.Database) *XDPoS { } } +// NewFullFaker creates an ethash consensus engine with a full fake scheme that +// accepts all blocks as valid, without checking any consensus rules whatsoever. +func NewFaker(db ethdb.Database) *XDPoS { + var fakeEngine *XDPoS + // Set any missing consensus parameters to their defaults + conf := params.TestXDPoSMockChainConfig.XDPoS + + // Allocate the snapshot caches and create the engine + BlockSigners, _ := lru.New(blockSignersCacheLimit) + recents, _ := lru.NewARC(inmemorySnapshots) + signatures, _ := lru.NewARC(inmemorySnapshots) + validatorSignatures, _ := lru.NewARC(inmemorySnapshots) + verifiedHeaders, _ := lru.NewARC(inmemorySnapshots) + fakeEngine = &XDPoS{ + config: conf, + db: db, + BlockSigners: BlockSigners, + recents: recents, + signatures: signatures, + verifiedHeaders: verifiedHeaders, + validatorSignatures: validatorSignatures, + proposals: make(map[common.Address]bool), + } + return fakeEngine +} + // Author implements consensus.Engine, returning the Ethereum address recovered // from the signature in the header's extra-data section. func (c *XDPoS) Author(header *types.Header) (common.Address, error) { @@ -349,6 +375,10 @@ func (c *XDPoS) verifyHeaderWithCache(chain consensus.ChainReader, header *types // looking those up from the database. This is useful for concurrently verifying // a batch of new headers. func (c *XDPoS) verifyHeader(chain consensus.ChainReader, header *types.Header, parents []*types.Header, fullVerify bool) error { + // If we're running a engine faking, accept any block as valid + if c.config.SkipValidation { + return nil + } if common.IsTestnet { fullVerify = false } @@ -1084,6 +1114,10 @@ func (c *XDPoS) CalcDifficulty(chain consensus.ChainReader, time uint64, parent } func (c *XDPoS) calcDifficulty(chain consensus.ChainReader, parent *types.Header, signer common.Address) *big.Int { + // If we're running a engine faking, skip calculation + if c.config.SkipValidation { + return big.NewInt(1) + } len, preIndex, curIndex, _, err := c.YourTurn(chain, parent, signer) if err != nil { return big.NewInt(int64(len + curIndex - preIndex)) diff --git a/contracts/blocksigner/blocksigner_test.go b/contracts/blocksigner/blocksigner_test.go index 0a649ea2f6..e3e0854d24 100644 --- a/contracts/blocksigner/blocksigner_test.go +++ b/contracts/blocksigner/blocksigner_test.go @@ -21,12 +21,13 @@ import ( "testing" "time" + "math/rand" + "github.com/XinFinOrg/XDPoSChain/accounts/abi/bind" "github.com/XinFinOrg/XDPoSChain/accounts/abi/bind/backends" "github.com/XinFinOrg/XDPoSChain/common" "github.com/XinFinOrg/XDPoSChain/core" "github.com/XinFinOrg/XDPoSChain/crypto" - "math/rand" ) var ( @@ -35,7 +36,7 @@ var ( ) func TestBlockSigner(t *testing.T) { - contractBackend := backends.NewSimulatedBackend(core.GenesisAlloc{addr: {Balance: big.NewInt(1000000000)}}) + contractBackend := backends.NewXDCSimulatedBackend(core.GenesisAlloc{addr: {Balance: big.NewInt(1000000000)}}, 10000000) transactOpts := bind.NewKeyedTransactor(key) blockSignerAddress, blockSigner, err := DeployBlockSigner(transactOpts, contractBackend, big.NewInt(99)) diff --git a/contracts/chequebook/cheque_test.go b/contracts/chequebook/cheque_test.go index dbf28f69e1..17b3237506 100644 --- a/contracts/chequebook/cheque_test.go +++ b/contracts/chequebook/cheque_test.go @@ -42,7 +42,7 @@ var ( ) func newTestBackend() *backends.SimulatedBackend { - return backends.NewSimulatedBackend(core.GenesisAlloc{ + return backends.NewXDCSimulatedBackend(core.GenesisAlloc{ addr0: {Balance: big.NewInt(1000000000)}, addr1: {Balance: big.NewInt(1000000000)}, addr2: {Balance: big.NewInt(1000000000)}, diff --git a/contracts/ens/ens_test.go b/contracts/ens/ens_test.go index 6b6facbccc..2705c75198 100644 --- a/contracts/ens/ens_test.go +++ b/contracts/ens/ens_test.go @@ -35,7 +35,7 @@ var ( ) func TestENS(t *testing.T) { - contractBackend := backends.NewSimulatedBackend(core.GenesisAlloc{addr: {Balance: big.NewInt(1000000000)}}) + contractBackend := backends.NewXDCSimulatedBackend(core.GenesisAlloc{addr: {Balance: big.NewInt(1000000000)}}, 10000000) transactOpts := bind.NewKeyedTransactor(key) ensAddr, ens, err := DeployENS(transactOpts, contractBackend) diff --git a/contracts/randomize/randomize_test.go b/contracts/randomize/randomize_test.go index 063b2832b6..bc35b86309 100644 --- a/contracts/randomize/randomize_test.go +++ b/contracts/randomize/randomize_test.go @@ -40,7 +40,7 @@ var ( ) func TestRandomize(t *testing.T) { - contractBackend := backends.NewSimulatedBackend(core.GenesisAlloc{addr: {Balance: big.NewInt(100000000000000)}}) + contractBackend := backends.NewXDCSimulatedBackend(core.GenesisAlloc{addr: {Balance: big.NewInt(100000000000000)}}, 10000000) transactOpts := bind.NewKeyedTransactor(key) transactOpts.GasLimit = 1000000 diff --git a/contracts/utils_test.go b/contracts/utils_test.go index abcf84aeb3..d267eda83e 100644 --- a/contracts/utils_test.go +++ b/contracts/utils_test.go @@ -19,6 +19,11 @@ import ( "bytes" "context" "crypto/ecdsa" + "math/big" + "math/rand" + "testing" + "time" + "github.com/XinFinOrg/XDPoSChain/accounts/abi/bind" "github.com/XinFinOrg/XDPoSChain/accounts/abi/bind/backends" "github.com/XinFinOrg/XDPoSChain/common" @@ -27,10 +32,6 @@ import ( "github.com/XinFinOrg/XDPoSChain/core" "github.com/XinFinOrg/XDPoSChain/core/types" "github.com/XinFinOrg/XDPoSChain/crypto" - "math/big" - "math/rand" - "testing" - "time" ) var ( @@ -46,7 +47,7 @@ var ( func getCommonBackend() *backends.SimulatedBackend { genesis := core.GenesisAlloc{acc1Addr: {Balance: big.NewInt(1000000000000)}} - backend := backends.NewSimulatedBackend(genesis) + backend := backends.NewXDCSimulatedBackend(genesis, 10000000) backend.Commit() return backend diff --git a/contracts/validator/validator_test.go b/contracts/validator/validator_test.go index 7cb3641bb9..a3a9b3cbc9 100644 --- a/contracts/validator/validator_test.go +++ b/contracts/validator/validator_test.go @@ -46,7 +46,7 @@ var ( ) func TestValidator(t *testing.T) { - contractBackend := backends.NewSimulatedBackend(core.GenesisAlloc{addr: {Balance: big.NewInt(1000000000)}}) + contractBackend := backends.NewXDCSimulatedBackend(core.GenesisAlloc{addr: {Balance: big.NewInt(1000000000)}}, 10000000) transactOpts := bind.NewKeyedTransactor(key) validatorCap := new(big.Int) @@ -82,7 +82,7 @@ func TestValidator(t *testing.T) { } func TestRewardBalance(t *testing.T) { - contractBackend := backends.NewSimulatedBackend(core.GenesisAlloc{ + contractBackend := backends.NewXDCSimulatedBackend(core.GenesisAlloc{ acc1Addr: {Balance: new(big.Int).SetUint64(10000000)}, acc2Addr: {Balance: new(big.Int).SetUint64(10000000)}, acc4Addr: {Balance: new(big.Int).SetUint64(10000000)}, diff --git a/core/blockchain.go b/core/blockchain.go index 1ccb46c13d..cf9bb23a28 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -152,10 +152,10 @@ type BlockChain struct { validator Validator // block and state validator interface vmConfig vm.Config - badBlocks *lru.Cache // Bad block cache - IPCEndpoint string - Client *ethclient.Client // Global ipc client instance. - + badBlocks *lru.Cache // Bad block cache + shouldPreserve func(*types.Block) bool // Function used to determine whether should preserve the given block. + IPCEndpoint string + Client bind.ContractBackend // Global ipc client instance. // Blocks hash array by block number // cache field for tracking finality purpose, can't use for tracking block vs block relationship blocksHashCache *lru.Cache @@ -1362,6 +1362,13 @@ func (bc *BlockChain) WriteBlockWithState(block *types.Block, receipts []*types. // Set new head. if status == CanonStatTy { bc.insert(block) + // prepare set of masternodes for the next epoch + if bc.chainConfig.XDPoS != nil && ((block.NumberU64() % bc.chainConfig.XDPoS.Epoch) == (bc.chainConfig.XDPoS.Epoch - bc.chainConfig.XDPoS.Gap)) { + err := bc.UpdateM1() + if err != nil { + log.Crit("Error when update masternodes set. Stopping node", "err", err) + } + } } // save cache BlockSigners if bc.chainConfig.XDPoS != nil && bc.chainConfig.IsTIPSigning(block.Number()) { @@ -1695,13 +1702,6 @@ func (bc *BlockChain) insertChain(chain types.Blocks) (int, []interface{}, []*ty CheckpointCh <- 1 } - // prepare set of masternodes for the next epoch - if (chain[i].NumberU64() % bc.chainConfig.XDPoS.Epoch) == (bc.chainConfig.XDPoS.Epoch - bc.chainConfig.XDPoS.Gap) { - err := bc.UpdateM1() - if err != nil { - log.Crit("Error when update masternodes set. Stopping node", "err", err) - } - } } } // Append a single chain head event if we've progressed the chain @@ -2039,14 +2039,6 @@ func (bc *BlockChain) insertBlock(block *types.Block) ([]interface{}, []*types.L CheckpointCh <- 1 } - // prepare set of masternodes for the next epoch - if (block.NumberU64() % bc.chainConfig.XDPoS.Epoch) == (bc.chainConfig.XDPoS.Epoch - bc.chainConfig.XDPoS.Gap) { - err := bc.UpdateM1() - if err != nil { - log.Error("Error when update masternodes set. Stopping node", "err", err) - os.Exit(1) - } - } } // Append a single chain head event if we've progressed the chain if status == CanonStatTy && bc.CurrentBlock().Hash() == block.Hash() { @@ -2193,6 +2185,13 @@ func (bc *BlockChain) reorg(oldBlock, newBlock *types.Block) error { return err } addedTxs = append(addedTxs, newChain[i].Transactions()...) + // prepare set of masternodes for the next epoch + if bc.chainConfig.XDPoS != nil && ((newChain[i].NumberU64() % bc.chainConfig.XDPoS.Epoch) == (bc.chainConfig.XDPoS.Epoch - bc.chainConfig.XDPoS.Gap)) { + err := bc.UpdateM1() + if err != nil { + log.Crit("Error when update masternodes set. Stopping node", "err", err) + } + } } // calculate the difference between deleted and added transactions diff := types.TxDifference(deletedTxs, addedTxs) @@ -2428,7 +2427,7 @@ func (bc *BlockChain) SubscribeLogsEvent(ch chan<- []*types.Log) event.Subscript } // Get current IPC Client. -func (bc *BlockChain) GetClient() (*ethclient.Client, error) { +func (bc *BlockChain) GetClient() (bind.ContractBackend, error) { if bc.Client == nil { // Inject ipc client global instance. client, err := ethclient.Dial(bc.IPCEndpoint) diff --git a/eth/api_backend.go b/eth/api_backend.go index f6bad9ead8..cb249b67ab 100644 --- a/eth/api_backend.go +++ b/eth/api_backend.go @@ -27,6 +27,7 @@ import ( "github.com/XinFinOrg/XDPoSChain/XDCx/tradingstate" "github.com/XinFinOrg/XDPoSChain/XDCxlending" + "github.com/XinFinOrg/XDPoSChain/accounts/abi/bind" "github.com/XinFinOrg/XDPoSChain/XDCx" @@ -45,7 +46,6 @@ import ( "github.com/XinFinOrg/XDPoSChain/core/vm" "github.com/XinFinOrg/XDPoSChain/eth/downloader" "github.com/XinFinOrg/XDPoSChain/eth/gasprice" - "github.com/XinFinOrg/XDPoSChain/ethclient" "github.com/XinFinOrg/XDPoSChain/ethdb" "github.com/XinFinOrg/XDPoSChain/event" "github.com/XinFinOrg/XDPoSChain/log" @@ -253,7 +253,8 @@ func (b *EthApiBackend) ServiceFilter(ctx context.Context, session *bloombits.Ma } } -func (b *EthApiBackend) GetIPCClient() (*ethclient.Client, error) { +func (b *EthApiBackend) GetIPCClient() (bind.ContractBackend, error) { + // func (b *EthApiBackend) GetIPCClient() (*ethclient.Client, error) { client, err := b.eth.blockchain.GetClient() if err != nil { return nil, err diff --git a/internal/ethapi/backend.go b/internal/ethapi/backend.go index 63ad4a095d..7f2d297baf 100644 --- a/internal/ethapi/backend.go +++ b/internal/ethapi/backend.go @@ -19,9 +19,11 @@ package ethapi import ( "context" + "math/big" + "github.com/XinFinOrg/XDPoSChain/XDCx/tradingstate" "github.com/XinFinOrg/XDPoSChain/XDCxlending" - "math/big" + "github.com/XinFinOrg/XDPoSChain/accounts/abi/bind" "github.com/XinFinOrg/XDPoSChain/XDCx" @@ -33,7 +35,6 @@ import ( "github.com/XinFinOrg/XDPoSChain/core/types" "github.com/XinFinOrg/XDPoSChain/core/vm" "github.com/XinFinOrg/XDPoSChain/eth/downloader" - "github.com/XinFinOrg/XDPoSChain/ethclient" "github.com/XinFinOrg/XDPoSChain/ethdb" "github.com/XinFinOrg/XDPoSChain/event" "github.com/XinFinOrg/XDPoSChain/params" @@ -83,7 +84,7 @@ type Backend interface { ChainConfig() *params.ChainConfig CurrentBlock() *types.Block - GetIPCClient() (*ethclient.Client, error) + GetIPCClient() (bind.ContractBackend, error) GetEngine() consensus.Engine GetRewardByHash(hash common.Hash) map[string]map[string]map[string]*big.Int diff --git a/les/api_backend.go b/les/api_backend.go index 84192196bb..d7909b81da 100644 --- a/les/api_backend.go +++ b/les/api_backend.go @@ -20,12 +20,14 @@ import ( "context" "encoding/json" "errors" - "github.com/XinFinOrg/XDPoSChain/XDCx/tradingstate" - "github.com/XinFinOrg/XDPoSChain/XDCxlending" "io/ioutil" "math/big" "path/filepath" + "github.com/XinFinOrg/XDPoSChain/XDCx/tradingstate" + "github.com/XinFinOrg/XDPoSChain/XDCxlending" + "github.com/XinFinOrg/XDPoSChain/accounts/abi/bind" + "github.com/XinFinOrg/XDPoSChain/XDCx" "github.com/XinFinOrg/XDPoSChain/accounts" @@ -39,7 +41,6 @@ import ( "github.com/XinFinOrg/XDPoSChain/core/vm" "github.com/XinFinOrg/XDPoSChain/eth/downloader" "github.com/XinFinOrg/XDPoSChain/eth/gasprice" - "github.com/XinFinOrg/XDPoSChain/ethclient" "github.com/XinFinOrg/XDPoSChain/ethdb" "github.com/XinFinOrg/XDPoSChain/event" "github.com/XinFinOrg/XDPoSChain/light" @@ -214,7 +215,9 @@ func (b *LesApiBackend) ServiceFilter(ctx context.Context, session *bloombits.Ma } } -func (b *LesApiBackend) GetIPCClient() (*ethclient.Client, error) { +// func (b *LesApiBackend) GetIPCClient() (*ethclient.Client, error) { +func (b *LesApiBackend) GetIPCClient() (bind.ContractBackend, error) { + // func (b *LesApiBackend) GetIPCClient() (bind.ContractBackend, error) { return nil, nil } diff --git a/miner/worker.go b/miner/worker.go index 537286bd0f..0ea43a9457 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -25,7 +25,6 @@ import ( "github.com/XinFinOrg/XDPoSChain/accounts" "math/big" - "os" "sync" "sync/atomic" "time" @@ -384,14 +383,6 @@ func (self *worker) wait() { if (block.NumberU64() % work.config.XDPoS.Epoch) == 0 { core.CheckpointCh <- 1 } - // prepare set of masternodes for the next epoch - if (block.NumberU64() % work.config.XDPoS.Epoch) == (work.config.XDPoS.Epoch - work.config.XDPoS.Gap) { - err := self.chain.UpdateM1() - if err != nil { - log.Error("Error when update masternodes set. Stopping node", "err", err) - os.Exit(1) - } - } } self.chain.UpdateBlocksHashCache(block) self.chain.PostChainEvents(events, logs) diff --git a/params/config.go b/params/config.go index e3a3ee0009..2523925021 100644 --- a/params/config.go +++ b/params/config.go @@ -111,8 +111,12 @@ var ( // 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}} 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} - 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)) + 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")}} + // 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}} + // 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} + TestRules = TestChainConfig.Rules(new(big.Int)) ) // ChainConfig is the core config which determines the blockchain settings. @@ -171,6 +175,7 @@ type XDPoSConfig struct { RewardCheckpoint uint64 `json:"rewardCheckpoint"` // Checkpoint block for calculate rewards. Gap uint64 `json:"gap"` // Gap time preparing for the next epoch FoudationWalletAddr common.Address `json:"foudationWalletAddr"` // Foundation Address Wallet + SkipValidation bool //Skip Block Validation for testing purpose } // String implements the stringer interface, returning the consensus engine details. diff --git a/tests/block_signer_test.go b/tests/block_signer_test.go new file mode 100644 index 0000000000..31b492e2dc --- /dev/null +++ b/tests/block_signer_test.go @@ -0,0 +1,842 @@ +package tests + +import ( + "bytes" + "context" + "encoding/hex" + "fmt" + "math/big" + "reflect" + "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/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: uint64(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(), bc, &header.Coinbase, gp, statedb, &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 +func TestNotUpdateSignerListIfNotOnGapBlock(t *testing.T) { + blockchain, backend, parentBlock := PrepareXDCTestBlockChain(t, 400) + parentSigners, err := GetSnapshotSigner(blockchain, parentBlock.Header()) + if err != nil { + t.Fatal(err) + } + t.Logf("Inserting block with propose at 401") + blockCoinbaseA := "0xaaa0000000000000000000000000000000000401" + tx, err := voteTX(37117, 0, acc1Addr.String()) + if err != nil { + t.Fatal(err) + } + + //Get from block validator error message + merkleRoot := "46234e9cd7e85a267f7f0435b15256a794a2f6d65cc98cdbd21dcd10a01d9772" + blockA, err := insertBlockTxs(blockchain, 401, blockCoinbaseA, parentBlock, []*types.Transaction{tx}, merkleRoot) + if err != nil { + t.Fatal(err) + } + + signers, err := GetSnapshotSigner(blockchain, blockA.Header()) + if err != nil { + t.Fatal(err) + } + + if signers[acc1Addr.Hex()] == true { + debugMessage(backend, signers, t) + t.Fatalf("account 1 should NOT sit in the signer list") + } + eq := reflect.DeepEqual(parentSigners, signers) + if eq { + t.Logf("Signers unchanged") + } else { + t.Fatalf("Singers should not be changed!") + } +} + +// 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) { + blockchain, _, parentBlock := PrepareXDCTestBlockChain(t, GAP-1) + // Insert block 450 + blockCoinBase := fmt.Sprintf("0x111000000000000000000000000000000%03d", 450) + merkleRoot := "35999dded35e8db12de7e6c1471eb9670c162eec616ecebbaf4fddd4676fb930" + block, err := insertBlock(blockchain, 450, blockCoinBase, parentBlock, merkleRoot) + if err != nil { + t.Fatal(err) + } + parentSigners, err := GetSnapshotSigner(blockchain, parentBlock.Header()) + if err != nil { + t.Fatal(err) + } + signers, err := GetSnapshotSigner(blockchain, block.Header()) + if err != nil { + t.Fatal(err) + } + + eq := reflect.DeepEqual(parentSigners, signers) + if eq { + t.Logf("Signers unchanged") + } else { + t.Fatalf("Singers should not be changed!") + } +} + +//Should call updateM1 at gap block, and update the snapshot if there are SM transactions involved +func TestUpdateSignerListIfVotedBeforeGap(t *testing.T) { + + blockchain, backend, parentBlock := PrepareXDCTestBlockChain(t, GAP-2) + // Insert first Block 449 + t.Logf("Inserting block with propose at 449...") + blockCoinbaseA := "0xaaa0000000000000000000000000000000000449" + tx, err := voteTX(37117, 0, acc1Addr.String()) + if err != nil { + t.Fatal(err) + } + + //Get from block validator error message + merkleRoot := "46234e9cd7e85a267f7f0435b15256a794a2f6d65cc98cdbd21dcd10a01d9772" + block449, err := insertBlockTxs(blockchain, 449, blockCoinbaseA, parentBlock, []*types.Transaction{tx}, merkleRoot) + if err != nil { + t.Fatal(err) + } + parentBlock = block449 + + signers, err := GetSnapshotSigner(blockchain, block449.Header()) + if err != nil { + t.Fatal(err) + } + // At block 449, we should not update signerList. we need to update it till block 450 gap block. + // Acc3 is the default account that is on the signerList + if signers[acc3Addr.Hex()] != true { + debugMessage(backend, signers, t) + t.Fatalf("account 3 should sit in the signer list") + } + if signers[acc1Addr.Hex()] == true { + debugMessage(backend, signers, t) + t.Fatalf("account 1 should NOT sit in the signer list") + } + + // Now, let's mine another block to trigger the GAP block signerList update + block450CoinbaseAddress := "0xaaa0000000000000000000000000000000000450" + merkleRoot = "46234e9cd7e85a267f7f0435b15256a794a2f6d65cc98cdbd21dcd10a01d9772" + block450, err := insertBlock(blockchain, 450, block450CoinbaseAddress, parentBlock, merkleRoot) + if err != nil { + t.Fatal(err) + } + + signers, err = GetSnapshotSigner(blockchain, block450.Header()) + // 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 { + debugMessage(backend, signers, t) + t.Fatalf("account 3 should NOT sit in the signer list") + } + if signers[acc1Addr.Hex()] != true { + debugMessage(backend, signers, t) + t.Fatalf("account 1 should sit in the signer list") + } +} + +//Should call updateM1 before gap block, and update the snapshot if there are SM transactions involved +func TestCallUpdateM1WithSmartContractTranscation(t *testing.T) { + + blockchain, backend, currentBlock := PrepareXDCTestBlockChain(t, GAP-1) + // Insert first Block 450 A + t.Logf("Inserting block with propose at 450 A...") + blockCoinbaseA := "0xaaa0000000000000000000000000000000000450" + tx, err := voteTX(37117, 0, acc1Addr.String()) + if err != nil { + t.Fatal(err) + } + + //Get from block validator error message + merkleRoot := "46234e9cd7e85a267f7f0435b15256a794a2f6d65cc98cdbd21dcd10a01d9772" + blockA, err := insertBlockTxs(blockchain, 450, blockCoinbaseA, currentBlock, []*types.Transaction{tx}, merkleRoot) + if err != nil { + t.Fatal(err) + } + + signers, err := GetSnapshotSigner(blockchain, blockA.Header()) + if err != nil { + t.Fatal(err) + } + if signers[acc1Addr.Hex()] != true { + debugMessage(backend, signers, t) + t.Fatalf("account 1 should sit in the signer list") + } +} + +// Should call updateM1 and update snapshot when a forked block(at gap block number) is inserted back into main chain (Edge case) +func TestCallUpdateM1WhenForkedBlockBackToMainChain(t *testing.T) { + + blockchain, backend, currentBlock := PrepareXDCTestBlockChain(t, GAP-1) + // Check initial signer, by default, acc3 is in the signerList + signers, err := GetSnapshotSigner(blockchain, blockchain.CurrentBlock().Header()) + if err != nil { + t.Fatal(err) + } + if signers[acc3Addr.Hex()] != true { + debugMessage(backend, signers, t) + t.Fatalf("acc3 should sit in the signer list") + } + if (signers[acc1Addr.Hex()] == true) || (signers[acc2Addr.Hex()] == true) { + debugMessage(backend, signers, t) + t.Fatalf("acc1,2should NOT sit in the signer list") + } + + // Insert first Block 450 A + t.Logf("Inserting block with propose at 450 A...") + blockCoinbaseA := "0xaaa0000000000000000000000000000000000450" + tx, err := voteTX(37117, 0, acc1Addr.String()) + if err != nil { + t.Fatal(err) + } + + merkleRoot := "46234e9cd7e85a267f7f0435b15256a794a2f6d65cc98cdbd21dcd10a01d9772" + blockA, err := insertBlockTxs(blockchain, 450, blockCoinbaseA, currentBlock, []*types.Transaction{tx}, merkleRoot) + if err != nil { + t.Fatal(err) + } + + signers, err = GetSnapshotSigner(blockchain, blockA.Header()) + if err != nil { + t.Fatal(err) + } + if signers[acc1Addr.Hex()] != true { + debugMessage(backend, signers, t) + t.Fatalf("account 1 should sit in the signer list") + } + if signers[acc2Addr.Hex()] == true || signers[acc3Addr.Hex()] == true { + debugMessage(backend, signers, t) + t.Fatalf("account 2,3 should NOT sit in the signer list") + } + + // Insert forked Block 450 B + t.Logf("Inserting block with propose for acc2 at 450 B...") + + blockCoinBase450B := "0xbbb0000000000000000000000000000000000450" + tx, err = voteTX(37117, 0, acc2Addr.String()) + if err != nil { + t.Fatal(err) + } + + merkleRoot = "068dfa09d7b4093441c0cc4d9807a71bc586f6101c072d939b214c21cd136eb3" + block450B, err := insertBlockTxs(blockchain, 450, blockCoinBase450B, currentBlock, []*types.Transaction{tx}, merkleRoot) + if err != nil { + t.Fatal(err) + } + signers, err = GetSnapshotSigner(blockchain, block450B.Header()) + if err != nil { + t.Fatal(err) + } + // Should not run the `updateM1` for forked chain, hence account3 still exit + if signers[acc3Addr.Hex()] != true { + debugMessage(backend, signers, t) + t.Fatalf("account 3 should sit in the signer list as previos block result") + } + if (signers[acc1Addr.Hex()] == true) || (signers[acc2Addr.Hex()] == true) { + debugMessage(backend, signers, t) + t.Fatalf("acc1,2should NOT sit in the signer list") + } + + //Insert block 451 parent is 451 B + t.Logf("Inserting block with propose at 451 B...") + + blockCoinBase451B := "0xbbb0000000000000000000000000000000000451" + merkleRoot = "068dfa09d7b4093441c0cc4d9807a71bc586f6101c072d939b214c21cd136eb3" + block451B, err := insertBlock(blockchain, 451, blockCoinBase451B, block450B, merkleRoot) + + if err != nil { + t.Fatal(err) + } + + signers, err = GetSnapshotSigner(blockchain, block450B.Header()) + if err != nil { + t.Fatal(err) + } + if signers[acc2Addr.Hex()] != true { + debugMessage(backend, signers, t) + t.Fatalf("account 2 should sit in the signer list") + } + if signers[acc1Addr.Hex()] == true || signers[acc3Addr.Hex()] == true { + debugMessage(backend, signers, t) + t.Fatalf("acc1,3should NOT sit in the signer list") + } + + signers, err = GetSnapshotSigner(blockchain, block451B.Header()) + if err != nil { + t.Fatal(err) + } + if signers[acc2Addr.Hex()] != true { + debugMessage(backend, signers, t) + t.Fatalf("account 2 should sit in the signer list") + } + if signers[acc1Addr.Hex()] == true || signers[acc3Addr.Hex()] == true { + debugMessage(backend, signers, t) + t.Fatalf("acc1,3should NOT sit in the signer list") + } + + signers, err = GetSnapshotSigner(blockchain, blockchain.CurrentBlock().Header()) + if err != nil { + t.Fatal(err) + } + if signers[acc2Addr.Hex()] != true { + debugMessage(backend, signers, t) + t.Fatalf("acc2Addr should sit in the signer list") + } + if signers[acc1Addr.Hex()] == true || signers[acc3Addr.Hex()] == true { + debugMessage(backend, signers, t) + t.Fatalf("acc1,3should NOT sit in the signer list") + } +} + +func TestStatesShouldBeUpdatedWhenForkedBlockBecameMainChainAtGapBlock(t *testing.T) { + + blockchain, backend, parentBlock := PrepareXDCTestBlockChain(t, GAP-1) + + state, err := blockchain.State() + t.Logf("Account %v have balance of: %v", acc1Addr.String(), state.GetBalance(acc1Addr)) + // Check initial signer + signers, err := GetSnapshotSigner(blockchain, blockchain.CurrentBlock().Header()) + if err != nil { + t.Fatal(err) + } + if signers[acc3Addr.Hex()] != true { + debugMessage(backend, signers, t) + t.Fatalf("acc3Addr should sit in the signer list") + } + + // Insert first Block 450 A + t.Logf("Inserting block with propose and transfer at 450 A...") + blockCoinbaseA := "0xaaa0000000000000000000000000000000000450" + tx, err := voteTX(58117, 0, acc1Addr.String()) + if err != nil { + t.Fatal(err) + } + + transferTransaction := transferTx(t, acc1Addr, 999) + + merkleRoot := "ea465415b60d88429f181fec9fae67c0f19cbf5a4fa10971d96d4faa57d96ffa" + blockA, err := insertBlockTxs(blockchain, 450, blockCoinbaseA, parentBlock, []*types.Transaction{tx, transferTransaction}, merkleRoot) + if err != nil { + t.Fatal(err) + } + state, err = blockchain.State() + 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 { + t.Fatalf("account 1 should have 10000000999 in balance") + } + + signers, err = GetSnapshotSigner(blockchain, blockA.Header()) + if err != nil { + t.Fatal(err) + } + if signers[acc1Addr.Hex()] != true { + debugMessage(backend, signers, t) + t.Fatalf("account 1 should sit in the signer list") + } + + // Insert forked Block 450 B + t.Logf("Inserting block with propose at 450 B...") + + blockCoinBase450B := "0xbbb0000000000000000000000000000000000450" + tx, err = voteTX(37117, 0, acc2Addr.String()) + if err != nil { + t.Fatal(err) + } + + transferTransaction = transferTx(t, acc1Addr, 888) + + merkleRoot = "184edaddeafc2404248f896ae46be503ae68949896c8eb6b6ad43695581e5022" + block450B, err := insertBlockTxs(blockchain, 450, blockCoinBase450B, parentBlock, []*types.Transaction{tx, transferTransaction}, merkleRoot) + if err != nil { + t.Fatal(err) + } + state, err = blockchain.State() + 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") + } + + signers, err = GetSnapshotSigner(blockchain, block450B.Header()) + if err != nil { + t.Fatal(err) + } + // Should not run the `updateM1` for forked chain, hence account3 still exit + if signers[acc3Addr.Hex()] != true { + debugMessage(backend, signers, t) + t.Fatalf("account 3 should sit in the signer list as previos block result") + } + + //Insert block 451 parent is 451 B + t.Logf("Inserting block with propose at 451 B...") + + blockCoinBase451B := "0xbbb0000000000000000000000000000000000451" + merkleRoot = "184edaddeafc2404248f896ae46be503ae68949896c8eb6b6ad43695581e5022" + block451B, err := insertBlock(blockchain, 451, blockCoinBase451B, block450B, merkleRoot) + + if err != nil { + t.Fatal(err) + } + + signers, err = GetSnapshotSigner(blockchain, block450B.Header()) + if err != nil { + t.Fatal(err) + } + if signers[acc2Addr.Hex()] != true { + debugMessage(backend, signers, t) + t.Fatalf("account 2 should sit in the signer list") + } + + signers, err = GetSnapshotSigner(blockchain, block451B.Header()) + if err != nil { + t.Fatal(err) + } + if signers[acc2Addr.Hex()] != true { + debugMessage(backend, signers, t) + t.Fatalf("account 2 should sit in the signer list") + } + + signers, err = GetSnapshotSigner(blockchain, blockchain.CurrentBlock().Header()) + if err != nil { + t.Fatal(err) + } + if signers[acc2Addr.Hex()] != true { + debugMessage(backend, signers, t) + t.Fatalf("acc2Addr should sit in the signer list") + } + state, err = 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)) + + if state.GetBalance(acc1Addr).Cmp(new(big.Int).SetUint64(10000000888)) != 0 { + t.Fatalf("account 1 should have 10000000888 in balance") + } +} + +func TestVoteShouldNotBeAffectedByFork(t *testing.T) { + blockchain, backend, parentBlock := PrepareXDCTestBlockChain(t, GAP-1) + // Check initial signer, by default, acc3 is in the signerList + signers, err := GetSnapshotSigner(blockchain, blockchain.CurrentBlock().Header()) + if err != nil { + t.Fatal(err) + } + if signers[acc3Addr.Hex()] != true { + debugMessage(backend, signers, t) + t.Fatalf("acc3 should sit in the signer list") + } + if (signers[acc1Addr.Hex()] == true) || (signers[acc2Addr.Hex()] == true) { + debugMessage(backend, signers, t) + t.Fatalf("acc1,2should NOT sit in the signer list") + } + + // Insert normal blocks 450 A + blockCoinBase450A := "0xaaa0000000000000000000000000000000000450" + merkleRoot := "35999dded35e8db12de7e6c1471eb9670c162eec616ecebbaf4fddd4676fb930" + block450A, err := insertBlock(blockchain, 450, blockCoinBase450A, parentBlock, merkleRoot) + if err != nil { + t.Fatal(err) + } + + // Insert 451 A with vote + blockCoinbase451A := "0xaaa0000000000000000000000000000000000451" + tx, err := voteTX(37117, 0, acc1Addr.String()) + if err != nil { + t.Fatal(err) + } + + merkleRoot = "46234e9cd7e85a267f7f0435b15256a794a2f6d65cc98cdbd21dcd10a01d9772" + block451A, err := insertBlockTxs(blockchain, 451, blockCoinbase451A, block450A, []*types.Transaction{tx}, merkleRoot) + if err != nil { + t.Fatal(err) + } + + // SignerList should be unchanged as the vote happen after GAP block + signers, err = GetSnapshotSigner(blockchain, block451A.Header()) + if err != nil { + t.Fatal(err) + } + if signers[acc1Addr.Hex()] == true { + debugMessage(backend, signers, t) + t.Fatalf("account 1 should NOT sit in the signer list") + } + if signers[acc3Addr.Hex()] != true { + debugMessage(backend, signers, t) + t.Fatalf("account 3 should sit in the signer list") + } + + // Now, we going to inject normal blocks of 450B, 451B and 452B. Because it's the longest, it will become the mainchain + // Insert forked Block 450 B + blockCoinBase450B := "0xbbb0000000000000000000000000000000000450" + merkleRoot = "35999dded35e8db12de7e6c1471eb9670c162eec616ecebbaf4fddd4676fb930" + block450B, err := insertBlock(blockchain, 450, blockCoinBase450B, parentBlock, merkleRoot) + if err != nil { + t.Fatal(err) + } + + blockCoinBase451B := "0xbbb0000000000000000000000000000000000451" + merkleRoot = "35999dded35e8db12de7e6c1471eb9670c162eec616ecebbaf4fddd4676fb930" + block451B, err := insertBlock(blockchain, 451, blockCoinBase451B, block450B, merkleRoot) + if err != nil { + t.Fatal(err) + } + + blockCoinBase452B := "0xbbb0000000000000000000000000000000000452" + merkleRoot = "35999dded35e8db12de7e6c1471eb9670c162eec616ecebbaf4fddd4676fb930" + block452B, err := insertBlock(blockchain, 452, blockCoinBase452B, block451B, merkleRoot) + if err != nil { + t.Fatal(err) + } + signers, err = GetSnapshotSigner(blockchain, block452B.Header()) + if err != nil { + t.Fatal(err) + } + + // Should run the `updateM1` for forked chain, but it should not be affected by the voted block 451A which is not on the mainchain anymore + if signers[acc3Addr.Hex()] != true { + debugMessage(backend, signers, t) + t.Fatalf("account 3 should sit in the signer list as previos block result") + } +}