Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

draft release v1.2.12 #1860

Merged
merged 9 commits into from
Sep 11, 2023
13 changes: 13 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,17 @@
# Changelog
## v1.2.12
FEATURE
* [\#1852](https://github.com/bnb-chain/bsc/pull/1852) discov: add hardcoded bootnodes

BUGFIX
* [\#1844](https://github.com/bnb-chain/bsc/pull/1844) crypto: Update BLST to v0.3.11
* [\#1854](https://github.com/bnb-chain/bsc/pull/1854) fetcher: no import blocks before or equal to the finalized height
* [\#1855](https://github.com/bnb-chain/bsc/pull/1855) eth/tracers: trace system tx should add intrinsicGas

IMPROVEMENT
* [\#1839](https://github.com/bnb-chain/bsc/pull/1839) Update init-network command
* [\#1858](https://github.com/bnb-chain/bsc/pull/1858) vote: check consensus key match vote key before voting

## v1.2.11
FEATURE
* [\#1797](https://github.com/bnb-chain/bsc/pull/1797) client: add FinalizedHeader/Block to use the fast finality
Expand Down
29 changes: 29 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,35 @@ APIs!**
- [BSC-Deploy](https://github.com/bnb-chain/node-deploy/): deploy tool for setting up both BNB Beacon Chain, BNB Smart Chain and the cross chain infrastructure between them.
- [BSC-Docker](https://github.com/bnb-chain/bsc-docker): deploy tool for setting up local BSC cluster in container.


## Running a bootnode

Bootnodes are super-lightweight nodes that are not behind a NAT and are running just discovery protocol. When you start up a node it should log your enode, which is a public identifier that others can use to connect to your node.

First the bootnode requires a key, which can be created with the following command, which will save a key to boot.key:

```
bootnode -genkey boot.key
```

This key can then be used to generate a bootnode as follows:

```
bootnode -nodekey boot.key -addr :30311 -network bsc
```

The choice of port passed to -addr is arbitrary.
The bootnode command returns the following logs to the terminal, confirming that it is running:

```
enode://3063d1c9e1b824cfbb7c7b6abafa34faec6bb4e7e06941d218d760acdd7963b274278c5c3e63914bd6d1b58504c59ec5522c56f883baceb8538674b92da48a96@127.0.0.1:0?discport=30311
Note: you're using cmd/bootnode, a developer tool.
We recommend using a regular node as bootstrap node for production deployments.
INFO [08-21|11:11:30.687] New local node record seq=1,692,616,290,684 id=2c9af1742f8f85ce ip=<nil> udp=0 tcp=0
INFO [08-21|12:11:30.753] New local node record seq=1,692,616,290,685 id=2c9af1742f8f85ce ip=54.217.128.118 udp=30311 tcp=0
INFO [09-01|02:46:26.234] New local node record seq=1,692,616,290,686 id=2c9af1742f8f85ce ip=34.250.32.100 udp=30311 tcp=0
```

## Contribution

Thank you for considering to help out with the source code! We welcome contributions
Expand Down
146 changes: 107 additions & 39 deletions cmd/geth/chaincmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (
"encoding/json"
"errors"
"fmt"
"io"
"net"
"os"
"path"
Expand Down Expand Up @@ -237,31 +238,17 @@ func initGenesis(ctx *cli.Context) error {
return nil
}

// initNetwork will bootstrap and initialize a new genesis block, and nodekey, config files for network nodes
func initNetwork(ctx *cli.Context) error {
initDir := ctx.String(utils.InitNetworkDir.Name)
if len(initDir) == 0 {
utils.Fatalf("init.dir is required")
}
size := ctx.Int(utils.InitNetworkSize.Name)
port := ctx.Int(utils.InitNetworkPort.Name)
ipStr := ctx.String(utils.InitNetworkIps.Name)
cfgFile := ctx.String(configFileFlag.Name)

if len(cfgFile) == 0 {
utils.Fatalf("config file is required")
}
func parseIps(ipStr string, size int) ([]string, error) {
var ips []string
if len(ipStr) != 0 {
ips = strings.Split(ipStr, ",")
if len(ips) != size {
utils.Fatalf("mismatch of size and length of ips")
return nil, errors.New("mismatch of size and length of ips")
}
for i := 0; i < size; i++ {
_, err := net.ResolveIPAddr("", ips[i])
if err != nil {
utils.Fatalf("invalid format of ip")
return err
return nil, errors.New("invalid format of ip")
}
}
} else {
Expand All @@ -270,61 +257,142 @@ func initNetwork(ctx *cli.Context) error {
ips[i] = "127.0.0.1"
}
}
return ips, nil
}

func createPorts(ipStr string, port int, size int) []int {
ports := make([]int, size)
if len(ipStr) == 0 { // localhost , so different ports
for i := 0; i < size; i++ {
ports[i] = port + i
}
} else { // different machines, keep same port
for i := 0; i < size; i++ {
ports[i] = port
}
}
return ports
}

// Create config for node i in the cluster
func createNodeConfig(baseConfig gethConfig, enodes []*enode.Node, ip string, port int, size int, i int) gethConfig {
baseConfig.Node.HTTPHost = ip
baseConfig.Node.P2P.ListenAddr = fmt.Sprintf(":%d", port+i)
baseConfig.Node.P2P.BootstrapNodes = make([]*enode.Node, size-1)
// Set the P2P connections between this node and the other nodes
for j := 0; j < i; j++ {
baseConfig.Node.P2P.BootstrapNodes[j] = enodes[j]
}
for j := i + 1; j < size; j++ {
baseConfig.Node.P2P.BootstrapNodes[j-1] = enodes[j]
}
return baseConfig
}

// Create configs for nodes in the cluster
func createNodeConfigs(baseConfig gethConfig, initDir string, ips []string, ports []int, size int) ([]gethConfig, error) {
// Create the nodes
enodes := make([]*enode.Node, size)
for i := 0; i < size; i++ {
stack, err := node.New(&baseConfig.Node)
if err != nil {
return nil, err
}
stack.Config().DataDir = path.Join(initDir, fmt.Sprintf("node%d", i))
pk := stack.Config().NodeKey()
enodes[i] = enode.NewV4(&pk.PublicKey, net.ParseIP(ips[i]), ports[i], ports[i])
}

// Create the configs
configs := make([]gethConfig, size)
for i := 0; i < size; i++ {
configs[i] = createNodeConfig(baseConfig, enodes, ips[i], ports[i], size, i)
}
return configs, nil
}

// initNetwork will bootstrap and initialize a new genesis block, and nodekey, config files for network nodes
func initNetwork(ctx *cli.Context) error {
initDir := ctx.String(utils.InitNetworkDir.Name)
if len(initDir) == 0 {
utils.Fatalf("init.dir is required")
}
size := ctx.Int(utils.InitNetworkSize.Name)
if size <= 0 {
utils.Fatalf("size should be greater than 0")
}
port := ctx.Int(utils.InitNetworkPort.Name)
if port <= 0 {
utils.Fatalf("port should be greater than 0")
}
ipStr := ctx.String(utils.InitNetworkIps.Name)
cfgFile := ctx.String(configFileFlag.Name)

if len(cfgFile) == 0 {
utils.Fatalf("config file is required")
}

ips, err := parseIps(ipStr, size)
if err != nil {
utils.Fatalf("Failed to pase ips string: %v", err)
}

ports := createPorts(ipStr, port, size)

// Make sure we have a valid genesis JSON
genesisPath := ctx.Args().First()
if len(genesisPath) == 0 {
utils.Fatalf("Must supply path to genesis JSON file")
}
file, err := os.Open(genesisPath)
inGenesisFile, err := os.Open(genesisPath)
if err != nil {
utils.Fatalf("Failed to read genesis file: %v", err)
}
defer file.Close()
defer inGenesisFile.Close()

genesis := new(core.Genesis)
if err := json.NewDecoder(file).Decode(genesis); err != nil {
if err := json.NewDecoder(inGenesisFile).Decode(genesis); err != nil {
utils.Fatalf("invalid genesis file: %v", err)
}
enodes := make([]*enode.Node, size)

// load config
var config gethConfig
err = loadConfig(cfgFile, &config)
if err != nil {
return err
}
config.Eth.Genesis = genesis

configs, err := createNodeConfigs(config, initDir, ips, ports, size)
if err != nil {
utils.Fatalf("Failed to create node configs: %v", err)
}

for i := 0; i < size; i++ {
stack, err := node.New(&config.Node)
// Write config.toml
configBytes, err := tomlSettings.Marshal(configs[i])
if err != nil {
return err
}
stack.Config().DataDir = path.Join(initDir, fmt.Sprintf("node%d", i))
pk := stack.Config().NodeKey()
enodes[i] = enode.NewV4(&pk.PublicKey, net.ParseIP(ips[i]), port, port)
}

for i := 0; i < size; i++ {
config.Node.HTTPHost = ips[i]
config.Node.P2P.StaticNodes = make([]*enode.Node, size-1)
for j := 0; j < i; j++ {
config.Node.P2P.StaticNodes[j] = enodes[j]
configFile, err := os.OpenFile(path.Join(initDir, fmt.Sprintf("node%d", i), "config.toml"), os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0644)
if err != nil {
return err
}
for j := i + 1; j < size; j++ {
config.Node.P2P.StaticNodes[j-1] = enodes[j]
defer configFile.Close()
configFile.Write(configBytes)

// Write the input genesis.json to the node's directory
outGenesisFile, err := os.OpenFile(path.Join(initDir, fmt.Sprintf("node%d", i), "genesis.json"), os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0644)
if err != nil {
return err
}
out, err := tomlSettings.Marshal(config)
_, err = inGenesisFile.Seek(0, io.SeekStart)
if err != nil {
return err
}
dump, err := os.OpenFile(path.Join(initDir, fmt.Sprintf("node%d", i), "config.toml"), os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0644)
_, err = io.Copy(outGenesisFile, inGenesisFile)
if err != nil {
return err
}
defer dump.Close()
dump.Write(out)
}
return nil
}
Expand Down
2 changes: 1 addition & 1 deletion consensus/consensus.go
Original file line number Diff line number Diff line change
Expand Up @@ -155,5 +155,5 @@ type PoSA interface {
GetJustifiedNumberAndHash(chain ChainHeaderReader, header *types.Header) (uint64, common.Hash, error)
GetFinalizedHeader(chain ChainHeaderReader, header *types.Header) *types.Header
VerifyVote(chain ChainHeaderReader, vote *types.VoteEnvelope) error
IsActiveValidatorAt(chain ChainHeaderReader, header *types.Header) bool
IsActiveValidatorAt(chain ChainHeaderReader, header *types.Header, checkVoteKeyFn func(bLSPublicKey *types.BLSPublicKey) bool) bool
}
7 changes: 4 additions & 3 deletions consensus/parlia/parlia.go
Original file line number Diff line number Diff line change
Expand Up @@ -1205,16 +1205,17 @@ func (p *Parlia) FinalizeAndAssemble(chain consensus.ChainHeaderReader, header *
return blk, receipts, nil
}

func (p *Parlia) IsActiveValidatorAt(chain consensus.ChainHeaderReader, header *types.Header) bool {
func (p *Parlia) IsActiveValidatorAt(chain consensus.ChainHeaderReader, header *types.Header, checkVoteKeyFn func(bLSPublicKey *types.BLSPublicKey) bool) bool {
number := header.Number.Uint64()
snap, err := p.snapshot(chain, number-1, header.ParentHash, nil)
if err != nil {
log.Error("failed to get the snapshot from consensus", "error", err)
return false
}
validators := snap.Validators
_, ok := validators[p.val]
return ok
validatorInfo, ok := validators[p.val]

return ok && (checkVoteKeyFn == nil || (validatorInfo != nil && checkVoteKeyFn(&validatorInfo.VoteAddress)))
}

// VerifyVote will verify: 1. If the vote comes from valid validators 2. If the vote's sourceNumber and sourceHash are correct
Expand Down
1 change: 1 addition & 0 deletions core/vm/logger.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ type EVMLogger interface {
// Transaction level
CaptureTxStart(gasLimit uint64)
CaptureTxEnd(restGas uint64)
CaptureSystemTxEnd(intrinsicGas uint64)
// Top call frame
CaptureStart(env *EVM, from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int)
CaptureEnd(output []byte, gasUsed uint64, err error)
Expand Down
18 changes: 16 additions & 2 deletions core/vote/vote_manager.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package vote

import (
"bytes"
"fmt"
"sync"

"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/consensus"
Expand Down Expand Up @@ -97,6 +99,7 @@ func (voteManager *VoteManager) loop() {
dlEventCh := events.Chan()

startVote := true
var once sync.Once
for {
select {
case ev := <-dlEventCh:
Expand Down Expand Up @@ -132,11 +135,22 @@ func (voteManager *VoteManager) loop() {

curHead := cHead.Block.Header()
// Check if cur validator is within the validatorSet at curHead
if !voteManager.engine.IsActiveValidatorAt(voteManager.chain, curHead) {
if !voteManager.engine.IsActiveValidatorAt(voteManager.chain, curHead,
func(bLSPublicKey *types.BLSPublicKey) bool {
brilliant-lx marked this conversation as resolved.
Show resolved Hide resolved
return bytes.Equal(voteManager.signer.PubKey[:], bLSPublicKey[:])
}) {
log.Debug("cur validator is not within the validatorSet at curHead")
continue
}

// Add VoteKey to `miner-info`
once.Do(func() {
minerInfo := metrics.Get("miner-info")
if minerInfo != nil {
minerInfo.(metrics.Label).Value()["VoteKey"] = common.Bytes2Hex(voteManager.signer.PubKey[:])
}
})

// Vote for curBlockHeader block.
vote := &types.VoteData{
TargetNumber: curHead.Number.Uint64(),
Expand Down Expand Up @@ -174,7 +188,7 @@ func (voteManager *VoteManager) loop() {
}
case event := <-voteManager.syncVoteCh:
voteMessage := event.Vote
if voteManager.eth.IsMining() || !voteManager.signer.UsingKey(&voteMessage.VoteAddress) {
if voteManager.eth.IsMining() || !bytes.Equal(voteManager.signer.PubKey[:], voteMessage.VoteAddress[:]) {
continue
}
if err := voteManager.journal.WriteVote(voteMessage); err != nil {
Expand Down
4 changes: 2 additions & 2 deletions core/vote/vote_pool_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -99,11 +99,11 @@ func (m *mockInvalidPOSA) VerifyVote(chain consensus.ChainHeaderReader, vote *ty
return nil
}

func (m *mockPOSA) IsActiveValidatorAt(chain consensus.ChainHeaderReader, header *types.Header) bool {
func (m *mockPOSA) IsActiveValidatorAt(chain consensus.ChainHeaderReader, header *types.Header, checkVoteKeyFn func(bLSPublicKey *types.BLSPublicKey) bool) bool {
return true
}

func (m *mockInvalidPOSA) IsActiveValidatorAt(chain consensus.ChainHeaderReader, header *types.Header) bool {
func (m *mockInvalidPOSA) IsActiveValidatorAt(chain consensus.ChainHeaderReader, header *types.Header, checkVoteKeyFn func(bLSPublicKey *types.BLSPublicKey) bool) bool {
return true
}

Expand Down
Loading
Loading