mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-27 15:16:43 +00:00
1392 lines
36 KiB
Go
1392 lines
36 KiB
Go
//go:build integration
|
|
|
|
// nolint
|
|
package bor
|
|
|
|
import (
|
|
"crypto/ecdsa"
|
|
"errors"
|
|
|
|
"os"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
|
|
"github.com/ethereum/go-ethereum/common/fdlimit"
|
|
"github.com/ethereum/go-ethereum/core"
|
|
|
|
"github.com/ethereum/go-ethereum/crypto"
|
|
"github.com/ethereum/go-ethereum/eth"
|
|
"github.com/ethereum/go-ethereum/log"
|
|
"github.com/ethereum/go-ethereum/node"
|
|
"github.com/ethereum/go-ethereum/p2p/enode"
|
|
)
|
|
|
|
var (
|
|
|
|
// Only this account is a validator for the 0th span
|
|
keyMilestone, _ = crypto.HexToECDSA(privKeyMilestone)
|
|
addrMilestone = crypto.PubkeyToAddress(keyMilestone.PublicKey) // 0x71562b71999873DB5b286dF957af199Ec94617F7
|
|
|
|
// This account is one the validators for 1st span (0-indexed)
|
|
key2Milestone, _ = crypto.HexToECDSA(privKey2Milestone)
|
|
addr2Milestone = crypto.PubkeyToAddress(key2Milestone.PublicKey) // 0x9fB29AAc15b9A4B7F17c3385939b007540f4d791
|
|
|
|
keysMilestone = []*ecdsa.PrivateKey{keyMilestone, key2Milestone}
|
|
)
|
|
|
|
const (
|
|
privKeyMilestone = "b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291"
|
|
privKey2Milestone = "9b28f36fbd67381120752d6172ecdcf10e06ab2d9a1367aac00cdcd6ac7855d3"
|
|
)
|
|
|
|
func TestMiningAfterLocking(t *testing.T) {
|
|
log.Root().SetHandler(log.LvlFilterHandler(log.LvlInfo, log.StreamHandler(os.Stderr, log.TerminalFormat(true))))
|
|
|
|
_, err := fdlimit.Raise(2048)
|
|
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
// Generate a batch of accounts to seal and fund with
|
|
faucets := make([]*ecdsa.PrivateKey, 128)
|
|
for i := 0; i < len(faucets); i++ {
|
|
faucets[i], _ = crypto.GenerateKey()
|
|
}
|
|
|
|
// Create an Ethash network based off of the Ropsten config
|
|
genesis := InitGenesis(t, faucets, "./testdata/genesis_2val.json", 8)
|
|
|
|
var (
|
|
stacks []*node.Node
|
|
nodes []*eth.Ethereum
|
|
enodes []*enode.Node
|
|
)
|
|
|
|
for i := 0; i < 2; i++ {
|
|
// Start the node and wait until it's up
|
|
stack, ethBackend, err := InitMiner(genesis, keysMilestone[i], true)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
defer stack.Close()
|
|
|
|
for stack.Server().NodeInfo().Ports.Listener == 0 {
|
|
time.Sleep(250 * time.Millisecond)
|
|
}
|
|
// Connect the node to all the previous ones
|
|
for _, n := range enodes {
|
|
stack.Server().AddPeer(n)
|
|
}
|
|
// Start tracking the node and its enode
|
|
stacks = append(stacks, stack)
|
|
nodes = append(nodes, ethBackend)
|
|
enodes = append(enodes, stack.Server().Self())
|
|
}
|
|
|
|
// Iterate over all the nodes and start mining
|
|
time.Sleep(3 * time.Second)
|
|
|
|
for _, node := range nodes {
|
|
if err := node.StartMining(); err != nil {
|
|
panic(err)
|
|
}
|
|
}
|
|
|
|
for {
|
|
|
|
// for block 0 to 7, the primary validator is node0
|
|
// for block 8 to 15, the primary validator is node1
|
|
// for block 16 to 23, the primary validator is node0
|
|
// for block 24 to 31, the primary validator is node1
|
|
blockHeaderVal0 := nodes[0].BlockChain().CurrentHeader()
|
|
blockHeaderVal1 := nodes[1].BlockChain().CurrentHeader()
|
|
|
|
//Lock the sprint at 8th block
|
|
if blockHeaderVal0.Number.Uint64() == 8 {
|
|
block8Hash := blockHeaderVal0.Hash()
|
|
|
|
nodes[0].Downloader().ChainValidator.LockMutex(uint64(8))
|
|
nodes[0].Downloader().ChainValidator.UnlockMutex(true, "MilestoneID1", uint64(8), block8Hash)
|
|
}
|
|
|
|
//Unlock the locked sprint
|
|
if blockHeaderVal0.Number.Uint64() == 12 {
|
|
nodes[0].Downloader().ChainValidator.UnlockSprint(8)
|
|
}
|
|
|
|
if blockHeaderVal1.Number.Uint64() == 16 {
|
|
block16Hash := blockHeaderVal1.Hash()
|
|
nodes[1].Downloader().ChainValidator.LockMutex(uint64(16))
|
|
nodes[1].Downloader().ChainValidator.UnlockMutex(true, "MilestoneID2", uint64(16), block16Hash)
|
|
}
|
|
|
|
if blockHeaderVal1.Number.Uint64() == 20 {
|
|
nodes[1].Downloader().ChainValidator.UnlockSprint(16)
|
|
}
|
|
|
|
if blockHeaderVal0.Number.Uint64() == 30 {
|
|
break
|
|
}
|
|
}
|
|
|
|
blockHeaderVal0 := nodes[0].BlockChain().GetHeaderByNumber(29)
|
|
blockHeaderVal1 := nodes[1].BlockChain().GetHeaderByNumber(29)
|
|
|
|
//Both nodes should have same blockheader at 29th block
|
|
assert.Equal(t, blockHeaderVal0, blockHeaderVal1)
|
|
|
|
milestoneListVal0 := nodes[0].Downloader().ChainValidator.GetMilestoneIDsList()
|
|
|
|
assert.Equal(t, len(milestoneListVal0), int(0))
|
|
|
|
milestoneListVal1 := nodes[1].Downloader().ChainValidator.GetMilestoneIDsList()
|
|
|
|
assert.Equal(t, len(milestoneListVal1), int(0))
|
|
}
|
|
|
|
func TestReorgingAfterLockingSprint(t *testing.T) {
|
|
t.Skip()
|
|
// t.Parallel()
|
|
|
|
log.Root().SetHandler(log.LvlFilterHandler(log.LvlInfo, log.StreamHandler(os.Stderr, log.TerminalFormat(true))))
|
|
|
|
_, err := fdlimit.Raise(2048)
|
|
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
// Generate a batch of accounts to seal and fund with
|
|
faucets := make([]*ecdsa.PrivateKey, 128)
|
|
for i := 0; i < len(faucets); i++ {
|
|
faucets[i], _ = crypto.GenerateKey()
|
|
}
|
|
|
|
// Create an Ethash network based off of the Ropsten config
|
|
genesis := InitGenesis(t, faucets, "./testdata/genesis_2val.json", 8)
|
|
|
|
var (
|
|
stacks []*node.Node
|
|
nodes []*eth.Ethereum
|
|
enodes []*enode.Node
|
|
)
|
|
|
|
for i := 0; i < 2; i++ {
|
|
// Start the node and wait until it's up
|
|
stack, ethBackend, err := InitMiner(genesis, keysMilestone[i], true)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
defer stack.Close()
|
|
|
|
for stack.Server().NodeInfo().Ports.Listener == 0 {
|
|
time.Sleep(250 * time.Millisecond)
|
|
}
|
|
// Connect the node to all the previous ones
|
|
for _, n := range enodes {
|
|
stack.Server().AddPeer(n)
|
|
}
|
|
// Start tracking the node and its enode
|
|
stacks = append(stacks, stack)
|
|
nodes = append(nodes, ethBackend)
|
|
enodes = append(enodes, stack.Server().Self())
|
|
}
|
|
|
|
// Iterate over all the nodes and start mining
|
|
time.Sleep(3 * time.Second)
|
|
|
|
for _, node := range nodes {
|
|
if err := node.StartMining(); err != nil {
|
|
panic(err)
|
|
}
|
|
}
|
|
|
|
for {
|
|
|
|
// for block 0 to 7, the primary validator is node0
|
|
// for block 8 to 15, the primary validator is node1
|
|
// for block 16 to 23, the primary validator is node0
|
|
// for block 24 to 31, the primary validator is node1
|
|
blockHeaderVal0 := nodes[0].BlockChain().CurrentHeader()
|
|
|
|
//Disconnect the peers at block 9
|
|
if blockHeaderVal0.Number.Uint64() == 9 {
|
|
|
|
stacks[0].Server().RemovePeer(enodes[1])
|
|
stacks[1].Server().RemovePeer(enodes[0])
|
|
}
|
|
|
|
//Node0 will be sealing out of turn and lock it till 12th block
|
|
if blockHeaderVal0.Number.Uint64() == 12 {
|
|
block12Hash := blockHeaderVal0.Hash()
|
|
nodes[0].Downloader().ChainValidator.LockMutex(uint64(12))
|
|
nodes[0].Downloader().ChainValidator.UnlockMutex(true, "MilestoneID1", uint64(12), block12Hash)
|
|
}
|
|
|
|
//Connect both the nodes
|
|
if blockHeaderVal0.Number.Uint64() == 14 {
|
|
stacks[0].Server().AddPeer(enodes[1])
|
|
stacks[1].Server().AddPeer(enodes[0])
|
|
}
|
|
|
|
authorVal0, err := nodes[0].Engine().Author(blockHeaderVal0)
|
|
|
|
//This will be true only when Node 0 has received the block from node 1 after 12th block.
|
|
if err == nil && blockHeaderVal0.Number.Uint64() > 12 && authorVal0 == nodes[1].AccountManager().Accounts()[0] {
|
|
break
|
|
}
|
|
|
|
if blockHeaderVal0.Number.Uint64() == 30 {
|
|
break
|
|
}
|
|
}
|
|
|
|
// check block 10 block ; expected author is node1 signer
|
|
blockHeader10Val0 := nodes[0].BlockChain().GetHeaderByNumber(10)
|
|
|
|
author10Val0, err := nodes[0].Engine().Author(blockHeader10Val0)
|
|
|
|
if err == nil {
|
|
assert.Equal(t, author10Val0, nodes[0].AccountManager().Accounts()[0])
|
|
}
|
|
|
|
blockHeader12Val0 := nodes[0].BlockChain().GetHeaderByNumber(12)
|
|
|
|
author12Val0, err := nodes[0].Engine().Author(blockHeader12Val0)
|
|
|
|
if err == nil {
|
|
assert.Equal(t, author12Val0, nodes[0].AccountManager().Accounts()[0])
|
|
}
|
|
|
|
//milestoneIDList should contain only one milestoneID
|
|
milestoneListVal1 := nodes[0].Downloader().ChainValidator.GetMilestoneIDsList()
|
|
|
|
assert.Equal(t, len(milestoneListVal1), int(1))
|
|
}
|
|
|
|
func TestReorgingAfterWhitelisting(t *testing.T) {
|
|
t.Skip()
|
|
// t.Parallel()
|
|
|
|
log.Root().SetHandler(log.LvlFilterHandler(log.LvlInfo, log.StreamHandler(os.Stderr, log.TerminalFormat(true))))
|
|
|
|
_, err := fdlimit.Raise(2048)
|
|
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
// Generate a batch of accounts to seal and fund with
|
|
faucets := make([]*ecdsa.PrivateKey, 128)
|
|
for i := 0; i < len(faucets); i++ {
|
|
faucets[i], _ = crypto.GenerateKey()
|
|
}
|
|
|
|
// Create an Ethash network based off of the Ropsten config
|
|
genesis := InitGenesis(t, faucets, "./testdata/genesis_2val.json", 8)
|
|
|
|
var (
|
|
stacks []*node.Node
|
|
nodes []*eth.Ethereum
|
|
enodes []*enode.Node
|
|
)
|
|
|
|
for i := 0; i < 2; i++ {
|
|
// Start the node and wait until it's up
|
|
stack, ethBackend, err := InitMiner(genesis, keysMilestone[i], true)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
defer stack.Close()
|
|
|
|
for stack.Server().NodeInfo().Ports.Listener == 0 {
|
|
time.Sleep(250 * time.Millisecond)
|
|
}
|
|
// Connect the node to all the previous ones
|
|
for _, n := range enodes {
|
|
stack.Server().AddPeer(n)
|
|
}
|
|
// Start tracking the node and its enode
|
|
stacks = append(stacks, stack)
|
|
nodes = append(nodes, ethBackend)
|
|
enodes = append(enodes, stack.Server().Self())
|
|
}
|
|
|
|
// Iterate over all the nodes and start mining
|
|
time.Sleep(3 * time.Second)
|
|
|
|
for _, node := range nodes {
|
|
if err := node.StartMining(); err != nil {
|
|
panic(err)
|
|
}
|
|
}
|
|
|
|
for {
|
|
// for block 0 to 7, the primary validator is node0
|
|
// for block 8 to 15, the primary validator is node1
|
|
// for block 16 to 23, the primary validator is node0
|
|
// for block 24 to 31, the primary validator is node1
|
|
blockHeaderVal0 := nodes[0].BlockChain().CurrentHeader()
|
|
|
|
//Disconnect the peers at block 9
|
|
if blockHeaderVal0.Number.Uint64() == 9 {
|
|
stacks[0].Server().RemovePeer(enodes[1])
|
|
stacks[1].Server().RemovePeer(enodes[0])
|
|
}
|
|
|
|
//Node0 will be sealing out of turn and lock it till 12th block
|
|
if blockHeaderVal0.Number.Uint64() == 12 {
|
|
block12Hash := blockHeaderVal0.Hash()
|
|
|
|
nodes[0].Downloader().ChainValidator.LockMutex(uint64(12))
|
|
nodes[0].Downloader().ChainValidator.UnlockMutex(true, "MilestoneID1", uint64(12), block12Hash)
|
|
}
|
|
|
|
if blockHeaderVal0.Number.Uint64() == 13 {
|
|
block13Hash := blockHeaderVal0.Hash()
|
|
nodes[0].Downloader().ChainValidator.ProcessMilestone(13, block13Hash)
|
|
}
|
|
|
|
if blockHeaderVal0.Number.Uint64() == 14 {
|
|
stacks[0].Server().AddPeer(enodes[1])
|
|
stacks[1].Server().AddPeer(enodes[0])
|
|
}
|
|
|
|
authorVal0, err := nodes[0].Engine().Author(blockHeaderVal0)
|
|
|
|
//This condition is true when Node 0 has received the block from node 1 after block 12
|
|
if err == nil && blockHeaderVal0.Number.Uint64() > 12 && authorVal0 == nodes[1].AccountManager().Accounts()[0] {
|
|
break
|
|
}
|
|
|
|
if blockHeaderVal0.Number.Uint64() == 30 {
|
|
break
|
|
}
|
|
}
|
|
|
|
arr := []uint64{10, 12, 13}
|
|
|
|
for _, val := range arr {
|
|
blockHeaderVal := nodes[0].BlockChain().GetHeaderByNumber(val)
|
|
|
|
authorVal, err := nodes[0].Engine().Author(blockHeaderVal)
|
|
|
|
if err == nil {
|
|
assert.Equal(t, authorVal, nodes[0].AccountManager().Accounts()[0])
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestPeerConnectionAfterWhitelisting(t *testing.T) {
|
|
t.Skip()
|
|
// t.Parallel()
|
|
|
|
log.Root().SetHandler(log.LvlFilterHandler(log.LvlInfo, log.StreamHandler(os.Stderr, log.TerminalFormat(true))))
|
|
|
|
_, err := fdlimit.Raise(2048)
|
|
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
// Generate a batch of accounts to seal and fund with
|
|
faucets := make([]*ecdsa.PrivateKey, 128)
|
|
for i := 0; i < len(faucets); i++ {
|
|
faucets[i], _ = crypto.GenerateKey()
|
|
}
|
|
|
|
// Create an Ethash network based off of the Ropsten config
|
|
genesis := InitGenesis(t, faucets, "./testdata/genesis_2val.json", 8)
|
|
|
|
var (
|
|
stacks []*node.Node
|
|
nodes []*eth.Ethereum
|
|
enodes []*enode.Node
|
|
)
|
|
|
|
for i := 0; i < 2; i++ {
|
|
// Start the node and wait until it's up
|
|
stack, ethBackend, err := InitMiner(genesis, keysMilestone[i], true)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
defer stack.Close()
|
|
|
|
for stack.Server().NodeInfo().Ports.Listener == 0 {
|
|
time.Sleep(250 * time.Millisecond)
|
|
}
|
|
// Connect the node to all the previous ones
|
|
for _, n := range enodes {
|
|
stack.Server().AddPeer(n)
|
|
}
|
|
// Start tracking the node and its enode
|
|
stacks = append(stacks, stack)
|
|
nodes = append(nodes, ethBackend)
|
|
enodes = append(enodes, stack.Server().Self())
|
|
}
|
|
|
|
// Iterate over all the nodes and start mining
|
|
time.Sleep(3 * time.Second)
|
|
|
|
for _, node := range nodes {
|
|
if err := node.StartMining(); err != nil {
|
|
panic(err)
|
|
}
|
|
}
|
|
|
|
disconnectFlag := false
|
|
|
|
for {
|
|
// for block 0 to 7, the primary validator is node0
|
|
// for block 8 to 15, the primary validator is node1
|
|
// for block 16 to 23, the primary validator is node0
|
|
// for block 24 to 31, the primary validator is node1
|
|
blockHeaderVal0 := nodes[0].BlockChain().CurrentHeader()
|
|
blockHeaderVal1 := nodes[1].BlockChain().CurrentHeader()
|
|
|
|
//Disconnect the peers at block 8
|
|
if blockHeaderVal0.Number.Uint64() == 8 && blockHeaderVal1.Number.Uint64() < 12 {
|
|
disconnectFlag = true
|
|
stacks[0].Server().RemovePeer(enodes[1])
|
|
stacks[1].Server().RemovePeer(enodes[0])
|
|
}
|
|
|
|
//Whitelist the validator0 with milestone at 12
|
|
if blockHeaderVal0.Number.Uint64() == 12 {
|
|
block12Hash := blockHeaderVal0.Hash()
|
|
nodes[0].Downloader().ChainValidator.ProcessMilestone(uint64(12), block12Hash)
|
|
}
|
|
|
|
///Whitelist the validator1 with milestone at 12
|
|
if blockHeaderVal1.Number.Uint64() == 12 {
|
|
block12Hash := blockHeaderVal1.Hash()
|
|
nodes[1].Downloader().ChainValidator.ProcessMilestone(uint64(12), block12Hash)
|
|
}
|
|
|
|
if blockHeaderVal0.Number.Uint64() > 12 && blockHeaderVal0.Number.Uint64() > 12 {
|
|
stacks[0].Server().AddPeer(enodes[1])
|
|
stacks[1].Server().AddPeer(enodes[0])
|
|
}
|
|
|
|
if blockHeaderVal0.Number.Uint64() == 30 {
|
|
break
|
|
}
|
|
}
|
|
|
|
// validator one peer count
|
|
val0PeerCount := stacks[0].Server().PeerCount()
|
|
val1PeerCount := stacks[1].Server().PeerCount()
|
|
|
|
if disconnectFlag {
|
|
assert.Equal(t, val0PeerCount, 0)
|
|
assert.Equal(t, val1PeerCount, 0)
|
|
|
|
blockHeader13Val0 := nodes[0].BlockChain().GetHeaderByNumber(13)
|
|
|
|
author13Val0, err := nodes[0].Engine().Author(blockHeader13Val0)
|
|
|
|
if err == nil {
|
|
assert.Equal(t, author13Val0, nodes[0].AccountManager().Accounts()[0])
|
|
}
|
|
|
|
blockHeader13Val1 := nodes[1].BlockChain().GetHeaderByNumber(13)
|
|
|
|
author13Val1, err := nodes[1].Engine().Author(blockHeader13Val1)
|
|
|
|
if err == nil {
|
|
assert.Equal(t, author13Val1, nodes[1].AccountManager().Accounts()[0])
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestReorgingFutureSprintAfterLocking(t *testing.T) {
|
|
t.Skip()
|
|
// t.Parallel()
|
|
|
|
log.Root().SetHandler(log.LvlFilterHandler(log.LvlInfo, log.StreamHandler(os.Stderr, log.TerminalFormat(true))))
|
|
|
|
_, err := fdlimit.Raise(2048)
|
|
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
// Generate a batch of accounts to seal and fund with
|
|
faucets := make([]*ecdsa.PrivateKey, 128)
|
|
for i := 0; i < len(faucets); i++ {
|
|
faucets[i], _ = crypto.GenerateKey()
|
|
}
|
|
|
|
// Create an Ethash network based off of the Ropsten config
|
|
genesis := InitGenesis(t, faucets, "./testdata/genesis_2val.json", 8)
|
|
|
|
var (
|
|
stacks []*node.Node
|
|
nodes []*eth.Ethereum
|
|
enodes []*enode.Node
|
|
)
|
|
for i := 0; i < 2; i++ {
|
|
// Start the node and wait until it's up
|
|
stack, ethBackend, err := InitMiner(genesis, keysMilestone[i], true)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
defer stack.Close()
|
|
|
|
for stack.Server().NodeInfo().Ports.Listener == 0 {
|
|
time.Sleep(250 * time.Millisecond)
|
|
}
|
|
// Connect the node to all the previous ones
|
|
for _, n := range enodes {
|
|
stack.Server().AddPeer(n)
|
|
}
|
|
// Start tracking the node and its enode
|
|
stacks = append(stacks, stack)
|
|
nodes = append(nodes, ethBackend)
|
|
enodes = append(enodes, stack.Server().Self())
|
|
}
|
|
|
|
// Iterate over all the nodes and start mining
|
|
time.Sleep(3 * time.Second)
|
|
|
|
for _, node := range nodes {
|
|
if err := node.StartMining(); err != nil {
|
|
panic(err)
|
|
}
|
|
}
|
|
|
|
for {
|
|
// for block 0 to 7, the primary validator is node0
|
|
// for block 8 to 15, the primary validator is node1
|
|
// for block 16 to 23, the primary validator is node0
|
|
// for block 24 to 31, the primary validator is node1
|
|
blockHeaderVal0 := nodes[0].BlockChain().CurrentHeader()
|
|
|
|
//Locking sprint at height 8
|
|
if blockHeaderVal0.Number.Uint64() == 8 {
|
|
block8Hash := blockHeaderVal0.Hash()
|
|
nodes[0].Downloader().ChainValidator.LockMutex(uint64(8))
|
|
nodes[0].Downloader().ChainValidator.UnlockMutex(true, "milestoneID1", uint64(8), block8Hash)
|
|
}
|
|
|
|
if blockHeaderVal0.Number.Uint64() == 30 {
|
|
break
|
|
}
|
|
}
|
|
|
|
node1Arr := []uint64{8, 15, 24}
|
|
|
|
for _, val := range node1Arr {
|
|
blockHeader := nodes[0].BlockChain().GetHeaderByNumber(val)
|
|
|
|
authorVal, err := nodes[0].Engine().Author(blockHeader)
|
|
|
|
if err == nil {
|
|
assert.Equal(t, authorVal, nodes[1].AccountManager().Accounts()[0])
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestReorgingFutureSprintAfterLockingOnSameHash(t *testing.T) {
|
|
t.Skip()
|
|
// t.Parallel()
|
|
|
|
log.Root().SetHandler(log.LvlFilterHandler(log.LvlInfo, log.StreamHandler(os.Stderr, log.TerminalFormat(true))))
|
|
|
|
_, err := fdlimit.Raise(2048)
|
|
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
// Generate a batch of accounts to seal and fund with
|
|
faucets := make([]*ecdsa.PrivateKey, 128)
|
|
for i := 0; i < len(faucets); i++ {
|
|
faucets[i], _ = crypto.GenerateKey()
|
|
}
|
|
|
|
// Create an Ethash network based off of the Ropsten config
|
|
genesis := InitGenesis(t, faucets, "./testdata/genesis_2val.json", 8)
|
|
|
|
var (
|
|
stacks []*node.Node
|
|
nodes []*eth.Ethereum
|
|
enodes []*enode.Node
|
|
)
|
|
for i := 0; i < 2; i++ {
|
|
// Start the node and wait until it's up
|
|
stack, ethBackend, err := InitMiner(genesis, keysMilestone[i], true)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
defer stack.Close()
|
|
|
|
for stack.Server().NodeInfo().Ports.Listener == 0 {
|
|
time.Sleep(250 * time.Millisecond)
|
|
}
|
|
// Connect the node to all the previous ones
|
|
for _, n := range enodes {
|
|
stack.Server().AddPeer(n)
|
|
}
|
|
// Start tracking the node and its enode
|
|
stacks = append(stacks, stack)
|
|
nodes = append(nodes, ethBackend)
|
|
enodes = append(enodes, stack.Server().Self())
|
|
}
|
|
|
|
// Iterate over all the nodes and start mining
|
|
time.Sleep(3 * time.Second)
|
|
|
|
for _, node := range nodes {
|
|
if err := node.StartMining(); err != nil {
|
|
panic(err)
|
|
}
|
|
}
|
|
|
|
for {
|
|
// for block 0 to 7, the primary validator is node0
|
|
// for block 8 to 15, the primary validator is node1
|
|
// for block 16 to 23, the primary validator is node0
|
|
// for block 24 to 31, the primary validator is node1
|
|
blockHeaderVal0 := nodes[0].BlockChain().CurrentHeader()
|
|
|
|
//Locking sprint at height 8
|
|
if blockHeaderVal0.Number.Uint64() == 8 {
|
|
block8Hash := blockHeaderVal0.Hash()
|
|
nodes[0].Downloader().ChainValidator.LockMutex(uint64(8))
|
|
nodes[0].Downloader().ChainValidator.UnlockMutex(true, "milestoneID1", uint64(8), block8Hash)
|
|
}
|
|
|
|
if blockHeaderVal0.Number.Uint64() == 30 {
|
|
break
|
|
}
|
|
|
|
}
|
|
|
|
node1Arr := []uint64{8, 15, 24}
|
|
|
|
for _, val := range node1Arr {
|
|
blockHeader := nodes[0].BlockChain().GetHeaderByNumber(val)
|
|
|
|
authorVal, err := nodes[0].Engine().Author(blockHeader)
|
|
|
|
if err == nil {
|
|
assert.Equal(t, authorVal, nodes[1].AccountManager().Accounts()[0])
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestReorgingAfterLockingOnDifferentHash(t *testing.T) {
|
|
t.Skip()
|
|
// t.Parallel()
|
|
|
|
log.Root().SetHandler(log.LvlFilterHandler(log.LvlInfo, log.StreamHandler(os.Stderr, log.TerminalFormat(true))))
|
|
|
|
_, err := fdlimit.Raise(2048)
|
|
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
// Generate a batch of accounts to seal and fund with
|
|
faucets := make([]*ecdsa.PrivateKey, 128)
|
|
for i := 0; i < len(faucets); i++ {
|
|
faucets[i], _ = crypto.GenerateKey()
|
|
}
|
|
|
|
// Create an Ethash network based off of the Ropsten config
|
|
genesis := InitGenesis(t, faucets, "./testdata/genesis_2val.json", 8)
|
|
|
|
var (
|
|
stacks []*node.Node
|
|
nodes []*eth.Ethereum
|
|
enodes []*enode.Node
|
|
)
|
|
for i := 0; i < 2; i++ {
|
|
// Start the node and wait until it's up
|
|
stack, ethBackend, err := InitMiner(genesis, keysMilestone[i], true)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
defer stack.Close()
|
|
|
|
for stack.Server().NodeInfo().Ports.Listener == 0 {
|
|
time.Sleep(250 * time.Millisecond)
|
|
}
|
|
|
|
// Connect the node to all the previous ones
|
|
for _, n := range enodes {
|
|
stack.Server().AddPeer(n)
|
|
}
|
|
|
|
// Start tracking the node and its enode
|
|
stacks = append(stacks, stack)
|
|
nodes = append(nodes, ethBackend)
|
|
enodes = append(enodes, stack.Server().Self())
|
|
}
|
|
|
|
// Iterate over all the nodes and start mining
|
|
time.Sleep(3 * time.Second)
|
|
|
|
for _, node := range nodes {
|
|
if err := node.StartMining(); err != nil {
|
|
panic(err)
|
|
}
|
|
}
|
|
|
|
//Peers are disconnected as we have not connected them
|
|
|
|
stacks[0].Server().RemovePeer(enodes[1])
|
|
stacks[1].Server().RemovePeer(enodes[0])
|
|
|
|
chain2HeadChNode0 := make(chan core.Chain2HeadEvent, 64)
|
|
chain2HeadChNode1 := make(chan core.Chain2HeadEvent, 64)
|
|
|
|
nodes[0].BlockChain().SubscribeChain2HeadEvent(chain2HeadChNode0)
|
|
nodes[1].BlockChain().SubscribeChain2HeadEvent(chain2HeadChNode1)
|
|
|
|
for {
|
|
// for block 0 to 7, the primary validator is node0
|
|
// for block 8 to 15, the primary validator is node1
|
|
// for block 16 to 23, the primary validator is node0
|
|
// for block 24 to 31, the primary validator is node1
|
|
blockHeaderVal0 := nodes[0].BlockChain().CurrentHeader()
|
|
blockHeaderVal1 := nodes[1].BlockChain().CurrentHeader()
|
|
|
|
//Locking sprint at height 7
|
|
if blockHeaderVal0.Number.Uint64() == 7 {
|
|
block7Hash := blockHeaderVal0.Hash()
|
|
nodes[0].Downloader().ChainValidator.LockMutex(uint64(7))
|
|
nodes[0].Downloader().ChainValidator.UnlockMutex(true, "milestoneID1", uint64(7), block7Hash)
|
|
}
|
|
|
|
if blockHeaderVal1.Number.Uint64() == 7 {
|
|
block7Hash := blockHeaderVal1.Hash()
|
|
nodes[1].Downloader().ChainValidator.LockMutex(uint64(7))
|
|
nodes[1].Downloader().ChainValidator.UnlockMutex(true, "milestoneID1", uint64(7), block7Hash)
|
|
}
|
|
|
|
if blockHeaderVal0.Number.Uint64() > 15 && blockHeaderVal1.Number.Uint64() > 15 {
|
|
stacks[0].Server().AddPeer(enodes[1])
|
|
stacks[1].Server().AddPeer(enodes[0])
|
|
}
|
|
|
|
select {
|
|
case ev := <-chain2HeadChNode0:
|
|
if ev.Type == core.Chain2HeadReorgEvent {
|
|
assert.Fail(t, "Node 0 should not get reorged")
|
|
break
|
|
|
|
}
|
|
|
|
case ev := <-chain2HeadChNode1:
|
|
if ev.Type == core.Chain2HeadReorgEvent {
|
|
assert.Fail(t, "Node 1 should not get reorged")
|
|
break
|
|
}
|
|
|
|
default:
|
|
time.Sleep(1 * time.Millisecond)
|
|
|
|
}
|
|
|
|
if blockHeaderVal0.Number.Uint64() == 30 {
|
|
break
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestReorgingAfterWhitelistingOnDifferentHash(t *testing.T) {
|
|
t.Skip()
|
|
// t.Parallel()
|
|
|
|
log.Root().SetHandler(log.LvlFilterHandler(log.LvlInfo, log.StreamHandler(os.Stderr, log.TerminalFormat(true))))
|
|
|
|
_, err := fdlimit.Raise(2048)
|
|
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
// Generate a batch of accounts to seal and fund with
|
|
faucets := make([]*ecdsa.PrivateKey, 128)
|
|
for i := 0; i < len(faucets); i++ {
|
|
faucets[i], _ = crypto.GenerateKey()
|
|
}
|
|
|
|
// Create an Ethash network based off of the Ropsten config
|
|
genesis := InitGenesis(t, faucets, "./testdata/genesis_2val.json", 8)
|
|
|
|
var (
|
|
stacks []*node.Node
|
|
nodes []*eth.Ethereum
|
|
enodes []*enode.Node
|
|
)
|
|
|
|
for i := 0; i < 2; i++ {
|
|
// Start the node and wait until it's up
|
|
stack, ethBackend, err := InitMiner(genesis, keysMilestone[i], true)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
defer stack.Close()
|
|
|
|
for stack.Server().NodeInfo().Ports.Listener == 0 {
|
|
time.Sleep(250 * time.Millisecond)
|
|
}
|
|
|
|
// Connect the node to all the previous ones
|
|
for _, n := range enodes {
|
|
stack.Server().AddPeer(n)
|
|
}
|
|
|
|
// Start tracking the node and its enode
|
|
stacks = append(stacks, stack)
|
|
nodes = append(nodes, ethBackend)
|
|
enodes = append(enodes, stack.Server().Self())
|
|
}
|
|
|
|
// Iterate over all the nodes and start mining
|
|
time.Sleep(3 * time.Second)
|
|
|
|
for _, node := range nodes {
|
|
if err := node.StartMining(); err != nil {
|
|
panic(err)
|
|
}
|
|
}
|
|
|
|
//Peers are disconnected as we have not connected them
|
|
|
|
stacks[0].Server().RemovePeer(enodes[1])
|
|
stacks[1].Server().RemovePeer(enodes[0])
|
|
|
|
chain2HeadChNode0 := make(chan core.Chain2HeadEvent, 64)
|
|
chain2HeadChNode1 := make(chan core.Chain2HeadEvent, 64)
|
|
|
|
nodes[0].BlockChain().SubscribeChain2HeadEvent(chain2HeadChNode0)
|
|
nodes[1].BlockChain().SubscribeChain2HeadEvent(chain2HeadChNode1)
|
|
|
|
for {
|
|
// for block 0 to 7, the primary validator is node0
|
|
// for block 8 to 15, the primary validator is node1
|
|
// for block 16 to 23, the primary validator is node0
|
|
// for block 24 to 31, the primary validator is node1
|
|
blockHeaderVal0 := nodes[0].BlockChain().CurrentHeader()
|
|
blockHeaderVal1 := nodes[1].BlockChain().CurrentHeader()
|
|
|
|
if blockHeaderVal0.Number.Uint64() == 20 {
|
|
break
|
|
}
|
|
|
|
//whitelisting at height
|
|
if blockHeaderVal0.Number.Uint64() == 1 {
|
|
block1Hash := blockHeaderVal0.Hash()
|
|
nodes[0].Downloader().ChainValidator.ProcessMilestone(uint64(1), block1Hash)
|
|
}
|
|
|
|
if blockHeaderVal1.Number.Uint64() == 1 {
|
|
block1Hash := blockHeaderVal1.Hash()
|
|
nodes[1].Downloader().ChainValidator.ProcessMilestone(uint64(1), block1Hash)
|
|
}
|
|
|
|
if blockHeaderVal0.Number.Uint64() > 1 && blockHeaderVal1.Number.Uint64() > 1 {
|
|
stacks[0].Server().AddPeer(enodes[1])
|
|
stacks[1].Server().AddPeer(enodes[0])
|
|
}
|
|
|
|
select {
|
|
case ev := <-chain2HeadChNode0:
|
|
if ev.Type == core.Chain2HeadReorgEvent {
|
|
assert.Fail(t, "Node 0 should not get reorged as it was whitelisted on different hash")
|
|
break
|
|
}
|
|
|
|
case ev := <-chain2HeadChNode1:
|
|
|
|
if ev.Type == core.Chain2HeadReorgEvent {
|
|
assert.Fail(t, "Node 1 should not get reorged as it was whiteliseted on different hash")
|
|
break
|
|
}
|
|
|
|
default:
|
|
time.Sleep(1 * time.Millisecond)
|
|
}
|
|
|
|
if blockHeaderVal0.Number.Uint64() == 30 {
|
|
break
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestNonMinerNodeWithWhitelisting(t *testing.T) {
|
|
t.Skip()
|
|
// t.Parallel()
|
|
|
|
log.Root().SetHandler(log.LvlFilterHandler(log.LvlInfo, log.StreamHandler(os.Stderr, log.TerminalFormat(true))))
|
|
|
|
_, err := fdlimit.Raise(2048)
|
|
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
// Generate a batch of accounts to seal and fund with
|
|
faucets := make([]*ecdsa.PrivateKey, 128)
|
|
for i := 0; i < len(faucets); i++ {
|
|
faucets[i], _ = crypto.GenerateKey()
|
|
}
|
|
|
|
// Create an Ethash network based off of the Ropsten config
|
|
genesis := InitGenesis(t, faucets, "./testdata/genesis_2val.json", 8)
|
|
|
|
var (
|
|
stacks []*node.Node
|
|
nodes []*eth.Ethereum
|
|
enodes []*enode.Node
|
|
)
|
|
|
|
for i := 0; i < 2; i++ {
|
|
// Start the node and wait until it's up
|
|
stack, ethBackend, err := InitMiner(genesis, keysMilestone[i], true)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
defer stack.Close()
|
|
|
|
for stack.Server().NodeInfo().Ports.Listener == 0 {
|
|
time.Sleep(250 * time.Millisecond)
|
|
}
|
|
|
|
// Connect the node to all the previous ones
|
|
for _, n := range enodes {
|
|
stack.Server().AddPeer(n)
|
|
}
|
|
|
|
// Start tracking the node and its enode
|
|
stacks = append(stacks, stack)
|
|
nodes = append(nodes, ethBackend)
|
|
enodes = append(enodes, stack.Server().Self())
|
|
}
|
|
|
|
// Iterate over all the nodes and start mining
|
|
time.Sleep(3 * time.Second)
|
|
|
|
//Only started the node 0 and keep the node 1 as non mining
|
|
err = nodes[0].StartMining()
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
for {
|
|
blockHeaderVal0 := nodes[0].BlockChain().CurrentHeader()
|
|
blockHeaderVal1 := nodes[1].BlockChain().CurrentHeader()
|
|
|
|
//Whitelisting milestone
|
|
if blockHeaderVal1.Number.Uint64() == 7 {
|
|
blockHash := blockHeaderVal1.Hash()
|
|
nodes[0].Downloader().ChainValidator.ProcessMilestone(blockHeaderVal1.Number.Uint64(), blockHash)
|
|
}
|
|
|
|
//Whitelisting milestone
|
|
if blockHeaderVal1.Number.Uint64() == 15 {
|
|
blockHash := blockHeaderVal1.Hash()
|
|
nodes[0].Downloader().ChainValidator.ProcessMilestone(blockHeaderVal1.Number.Uint64(), blockHash)
|
|
}
|
|
|
|
//Whitelisting milestone
|
|
if blockHeaderVal1.Number.Uint64() == 23 {
|
|
blockHash := blockHeaderVal1.Hash()
|
|
nodes[0].Downloader().ChainValidator.ProcessMilestone(blockHeaderVal1.Number.Uint64(), blockHash)
|
|
}
|
|
|
|
if blockHeaderVal0.Number.Uint64() == 30 {
|
|
break
|
|
}
|
|
}
|
|
|
|
for i := uint64(0); i < nodes[1].BlockChain().CurrentBlock().Number.Uint64(); i++ {
|
|
blockHeader := nodes[1].BlockChain().GetHeaderByNumber(i)
|
|
|
|
authorVal, err := nodes[1].Engine().Author(blockHeader)
|
|
|
|
if err == nil {
|
|
assert.Equal(t, authorVal, nodes[0].AccountManager().Accounts()[0])
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestNonMinerNodeWithTryToLock(t *testing.T) {
|
|
t.Skip()
|
|
// t.Parallel()
|
|
|
|
log.Root().SetHandler(log.LvlFilterHandler(log.LvlInfo, log.StreamHandler(os.Stderr, log.TerminalFormat(true))))
|
|
|
|
_, err := fdlimit.Raise(2048)
|
|
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
// Generate a batch of accounts to seal and fund with
|
|
faucets := make([]*ecdsa.PrivateKey, 128)
|
|
for i := 0; i < len(faucets); i++ {
|
|
faucets[i], _ = crypto.GenerateKey()
|
|
}
|
|
|
|
// Create an Ethash network based off of the Ropsten config
|
|
genesis := InitGenesis(t, faucets, "./testdata/genesis_2val.json", 8)
|
|
|
|
var (
|
|
stacks []*node.Node
|
|
nodes []*eth.Ethereum
|
|
enodes []*enode.Node
|
|
)
|
|
for i := 0; i < 2; i++ {
|
|
// Start the node and wait until it's up
|
|
stack, ethBackend, err := InitMiner(genesis, keysMilestone[i], true)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
defer stack.Close()
|
|
|
|
for stack.Server().NodeInfo().Ports.Listener == 0 {
|
|
time.Sleep(250 * time.Millisecond)
|
|
}
|
|
|
|
// Connect the node to all the previous ones
|
|
for _, n := range enodes {
|
|
stack.Server().AddPeer(n)
|
|
}
|
|
|
|
// Start tracking the node and its enode
|
|
stacks = append(stacks, stack)
|
|
nodes = append(nodes, ethBackend)
|
|
enodes = append(enodes, stack.Server().Self())
|
|
}
|
|
|
|
// Iterate over all the nodes and start mining
|
|
time.Sleep(3 * time.Second)
|
|
|
|
//Only started the node 0 and keep the node 1 as non mining
|
|
err = nodes[0].StartMining()
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
for {
|
|
blockHeaderVal0 := nodes[0].BlockChain().CurrentHeader()
|
|
blockHeaderVal1 := nodes[1].BlockChain().CurrentHeader()
|
|
|
|
//Asking for the vote
|
|
if blockHeaderVal1.Number.Uint64() == 7 {
|
|
blockHash := blockHeaderVal1.Hash()
|
|
_, _ = nodes[1].APIBackend.GetVoteOnHash(nil, 0, 7, "0x"+blockHash.String(), "MilestoneID1")
|
|
|
|
}
|
|
|
|
//Asking for the vote
|
|
if blockHeaderVal1.Number.Uint64() == 15 {
|
|
blockHash := blockHeaderVal1.Hash()
|
|
_, _ = nodes[1].APIBackend.GetVoteOnHash(nil, 0, 7, "0x"+blockHash.String(), "MilestoneID2")
|
|
}
|
|
|
|
//Asking for the vote
|
|
if blockHeaderVal1.Number.Uint64() == 23 {
|
|
blockHash := blockHeaderVal1.Hash()
|
|
_, _ = nodes[1].APIBackend.GetVoteOnHash(nil, 0, 7, "0x"+blockHash.String(), "MilestoneID3")
|
|
}
|
|
|
|
milestoneList := nodes[0].Downloader().ChainValidator.GetMilestoneIDsList()
|
|
if len(milestoneList) > 0 {
|
|
assert.Fail(t, "MilestoneList should be of zero length")
|
|
}
|
|
|
|
if blockHeaderVal0.Number.Uint64() == 30 {
|
|
break
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestRewind(t *testing.T) {
|
|
t.Skip()
|
|
// t.Parallel()
|
|
|
|
log.Root().SetHandler(log.LvlFilterHandler(log.LvlInfo, log.StreamHandler(os.Stderr, log.TerminalFormat(true))))
|
|
|
|
_, err := fdlimit.Raise(2048)
|
|
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
// Generate a batch of accounts to seal and fund with
|
|
faucets := make([]*ecdsa.PrivateKey, 128)
|
|
for i := 0; i < len(faucets); i++ {
|
|
faucets[i], _ = crypto.GenerateKey()
|
|
}
|
|
|
|
// Create an Ethash network based off of the Ropsten config
|
|
genesis := InitGenesis(t, faucets, "./testdata/genesis_2val.json", 8)
|
|
|
|
var (
|
|
stacks []*node.Node
|
|
nodes []*eth.Ethereum
|
|
enodes []*enode.Node
|
|
)
|
|
for i := 0; i < 2; i++ {
|
|
// Start the node and wait until it's up
|
|
stack, ethBackend, err := InitMiner(genesis, keysMilestone[i], true)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
defer stack.Close()
|
|
|
|
for stack.Server().NodeInfo().Ports.Listener == 0 {
|
|
time.Sleep(250 * time.Millisecond)
|
|
}
|
|
|
|
// Connect the node to all the previous ones
|
|
for _, n := range enodes {
|
|
stack.Server().AddPeer(n)
|
|
}
|
|
|
|
// Start tracking the node and its enode
|
|
stacks = append(stacks, stack)
|
|
nodes = append(nodes, ethBackend)
|
|
enodes = append(enodes, stack.Server().Self())
|
|
}
|
|
|
|
// Iterate over all the nodes and start mining
|
|
time.Sleep(3 * time.Second)
|
|
|
|
for _, node := range nodes {
|
|
if err := node.StartMining(); err != nil {
|
|
panic(err)
|
|
}
|
|
}
|
|
|
|
// step1 := false
|
|
// step2 := false
|
|
// step3 := false
|
|
step4 := false
|
|
|
|
for {
|
|
blockHeaderVal0 := nodes[0].BlockChain().CurrentHeader()
|
|
blockHeaderVal1 := nodes[1].BlockChain().CurrentHeader()
|
|
|
|
// if blockHeaderVal1.Number.Uint64() == 20 && !step1 {
|
|
// nodes[1].BlockChain().SetHead(2)
|
|
|
|
// step1 = true
|
|
// }
|
|
|
|
// if blockHeaderVal1.Number.Uint64() == 40 && !step2 {
|
|
// nodes[1].BlockChain().SetHead(2)
|
|
|
|
// step2 = true
|
|
// }
|
|
|
|
// if blockHeaderVal1.Number.Uint64() == 80 && !step3 {
|
|
// nodes[1].BlockChain().SetHead(2)
|
|
|
|
// step3 = true
|
|
// }
|
|
|
|
// if blockHeaderVal1.Number.Uint64() == 120 && !step4 {
|
|
// nodes[1].BlockChain().SetHead(2)
|
|
|
|
// step4 = true
|
|
// }
|
|
|
|
if blockHeaderVal1.Number.Uint64() == 180 && !step4 {
|
|
ch := make(chan struct{})
|
|
nodes[1].Miner().Stop(ch)
|
|
<-ch
|
|
err := nodes[1].BlockChain().SetHead(2)
|
|
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
err = nodes[1].StartMining()
|
|
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
step4 = true
|
|
}
|
|
|
|
if blockHeaderVal0.Number.Uint64() == 200 {
|
|
break
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestRewinding(t *testing.T) {
|
|
t.Skip()
|
|
// t.Parallel()
|
|
|
|
log.Root().SetHandler(log.LvlFilterHandler(log.LvlInfo, log.StreamHandler(os.Stderr, log.TerminalFormat(true))))
|
|
|
|
_, err := fdlimit.Raise(2048)
|
|
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
// Generate a batch of accounts to seal and fund with
|
|
faucets := make([]*ecdsa.PrivateKey, 128)
|
|
for i := 0; i < len(faucets); i++ {
|
|
faucets[i], _ = crypto.GenerateKey()
|
|
}
|
|
|
|
// Create an Ethash network based off of the Ropsten config
|
|
genesis := InitGenesis(t, faucets, "./testdata/genesis_2val.json", 8)
|
|
|
|
var (
|
|
stacks []*node.Node
|
|
nodes []*eth.Ethereum
|
|
enodes []*enode.Node
|
|
)
|
|
for i := 0; i < 2; i++ {
|
|
// Start the node and wait until it's up
|
|
stack, ethBackend, err := InitMiner(genesis, keysMilestone[i], true)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
defer stack.Close()
|
|
|
|
for stack.Server().NodeInfo().Ports.Listener == 0 {
|
|
time.Sleep(250 * time.Millisecond)
|
|
}
|
|
|
|
// Connect the node to all the previous ones
|
|
for _, n := range enodes {
|
|
stack.Server().AddPeer(n)
|
|
}
|
|
|
|
// Start tracking the node and its enode
|
|
stacks = append(stacks, stack)
|
|
nodes = append(nodes, ethBackend)
|
|
enodes = append(enodes, stack.Server().Self())
|
|
}
|
|
|
|
// Iterate over all the nodes and start mining
|
|
time.Sleep(3 * time.Second)
|
|
|
|
//Start mining
|
|
for _, node := range nodes {
|
|
if err := node.StartMining(); err != nil {
|
|
panic(err)
|
|
}
|
|
}
|
|
|
|
var step1 = false
|
|
var step2 = false
|
|
|
|
for {
|
|
blockHeaderVal0 := nodes[0].BlockChain().CurrentHeader()
|
|
blockHeaderVal1 := nodes[1].BlockChain().CurrentHeader()
|
|
|
|
//Processing the milestone
|
|
if blockHeaderVal0.Number.Uint64() == 7 {
|
|
blockHash := blockHeaderVal1.Hash()
|
|
nodes[0].Downloader().ChainValidator.ProcessMilestone(blockHeaderVal1.Number.Uint64(), blockHash)
|
|
}
|
|
|
|
//Verify the wrong hash to rewind back
|
|
if blockHeaderVal0.Number.Uint64() == 15 && !step1 {
|
|
_, _ = borVerify(nodes[0], 8, 15, "LocalHash", "RootHash", 15, 7)
|
|
step1 = true
|
|
}
|
|
|
|
//Check for the rewind
|
|
if step1 && blockHeaderVal0.Number.Uint64() <= 6 {
|
|
assert.Fail(t, "Node1 chain rewound to more than expected number")
|
|
}
|
|
|
|
//Verify the wrong hash
|
|
if blockHeaderVal0.Number.Uint64() == 270 && !step2 {
|
|
_, _ = borVerify(nodes[0], 8, 15, "LocalHash", "RootHash", 270, 7)
|
|
step2 = true
|
|
}
|
|
|
|
//Check for the rewind
|
|
if step2 && blockHeaderVal0.Number.Uint64() <= 14 {
|
|
assert.Fail(t, "Node1 chain rewound to more than expected number")
|
|
}
|
|
|
|
if blockHeaderVal0.Number.Uint64() == 300 {
|
|
break
|
|
}
|
|
}
|
|
}
|
|
|
|
var (
|
|
// errMissingBlocks is returned when we don't have the blocks locally, yet.
|
|
errMissingBlocks = errors.New("missing blocks")
|
|
|
|
// errRootHash is returned when we aren't able to calculate the root hash
|
|
// locally for a range of blocks.
|
|
errRootHash = errors.New("failed to get local root hash")
|
|
|
|
// errHashMismatch is returned when the local hash doesn't match
|
|
// with the hash of checkpoint/milestone. It is the root hash of blocks
|
|
// in case of checkpoint and is end block hash in case of milestones.
|
|
errHashMismatch = errors.New("hash mismatch")
|
|
|
|
// errEndBlock is returned when we're unable to fetch a block locally.
|
|
errEndBlock = errors.New("failed to get end block")
|
|
|
|
// errBlockNumberConversion is returned when we get err in parsing hexautil block number
|
|
errBlockNumberConversion = errors.New("failed to parse the block number")
|
|
)
|
|
|
|
func borVerify(eth *eth.Ethereum, start uint64, end uint64, rootHash string, localHash string, head uint64, lastMilestone uint64) (string, error) {
|
|
//nolint
|
|
if localHash != rootHash {
|
|
var rewindTo uint64
|
|
rewindTo = lastMilestone
|
|
|
|
if head-rewindTo > 255 {
|
|
rewindTo = head - 254
|
|
}
|
|
|
|
rewindBack(eth, rewindTo)
|
|
|
|
return "", errHashMismatch
|
|
}
|
|
|
|
return "", nil
|
|
}
|
|
|
|
// Stop the miner if the mining process is running and rewind back the chain
|
|
func rewindBack(eth *eth.Ethereum, rewindTo uint64) {
|
|
if eth.Miner().Mining() {
|
|
ch := make(chan struct{})
|
|
eth.Miner().Stop(ch)
|
|
<-ch
|
|
rewind(eth, rewindTo)
|
|
|
|
err := eth.StartMining()
|
|
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
} else {
|
|
rewind(eth, rewindTo)
|
|
}
|
|
}
|
|
|
|
func rewind(eth *eth.Ethereum, rewindTo uint64) {
|
|
log.Warn("Rewinding chain to :", rewindTo, "block number")
|
|
err := eth.BlockChain().SetHead(rewindTo)
|
|
|
|
if err != nil {
|
|
log.Error("Error while rewinding the chain to", "Block Number", rewindTo, "Error", err)
|
|
}
|
|
}
|