go-ethereum/tests/bor/bor_milestone_test.go
2023-09-20 15:57:37 +05:30

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)
}
}