mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-27 23:26:44 +00:00
jaipur fork (#269)
* jaipur fork * add check * review comments * test case * fix few changes * Change condition * review comments * type conversion * Update mumbai.go * Update config.go * Update config.go Co-authored-by: Ferran Borreguero <ferranbt@protonmail.com>
This commit is contained in:
parent
467e53b2ac
commit
a10f79dc27
9 changed files with 168 additions and 31 deletions
|
|
@ -28,10 +28,14 @@ var mainnetBor = &Chain{
|
|||
MuirGlacierBlock: big.NewInt(3395000),
|
||||
BerlinBlock: big.NewInt(14750000),
|
||||
Bor: ¶ms.BorConfig{
|
||||
Period: 2,
|
||||
ProducerDelay: 6,
|
||||
Sprint: 64,
|
||||
BackupMultiplier: 2,
|
||||
Period: map[string]uint64{
|
||||
"0": 2,
|
||||
},
|
||||
ProducerDelay: 6,
|
||||
Sprint: 64,
|
||||
BackupMultiplier: map[string]uint64{
|
||||
"0": 2,
|
||||
},
|
||||
ValidatorContract: "0x0000000000000000000000000000000000001000",
|
||||
StateReceiverContract: "0x0000000000000000000000000000000000001001",
|
||||
OverrideStateSyncRecords: map[string]int{
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
|
|
@ -123,7 +123,7 @@ var (
|
|||
type SignerFn func(accounts.Account, string, []byte) ([]byte, error)
|
||||
|
||||
// ecrecover extracts the Ethereum account address from a signed header.
|
||||
func ecrecover(header *types.Header, sigcache *lru.ARCCache) (common.Address, error) {
|
||||
func ecrecover(header *types.Header, sigcache *lru.ARCCache, c *params.BorConfig) (common.Address, error) {
|
||||
// If the signature's already cached, return that
|
||||
hash := header.Hash()
|
||||
if address, known := sigcache.Get(hash); known {
|
||||
|
|
@ -136,7 +136,7 @@ func ecrecover(header *types.Header, sigcache *lru.ARCCache) (common.Address, er
|
|||
signature := header.Extra[len(header.Extra)-extraSeal:]
|
||||
|
||||
// Recover the public key and the Ethereum address
|
||||
pubkey, err := crypto.Ecrecover(SealHash(header).Bytes(), signature)
|
||||
pubkey, err := crypto.Ecrecover(SealHash(header, c).Bytes(), signature)
|
||||
if err != nil {
|
||||
return common.Address{}, err
|
||||
}
|
||||
|
|
@ -148,15 +148,15 @@ func ecrecover(header *types.Header, sigcache *lru.ARCCache) (common.Address, er
|
|||
}
|
||||
|
||||
// SealHash returns the hash of a block prior to it being sealed.
|
||||
func SealHash(header *types.Header) (hash common.Hash) {
|
||||
func SealHash(header *types.Header, c *params.BorConfig) (hash common.Hash) {
|
||||
hasher := sha3.NewLegacyKeccak256()
|
||||
encodeSigHeader(hasher, header)
|
||||
encodeSigHeader(hasher, header, c)
|
||||
hasher.Sum(hash[:0])
|
||||
return hash
|
||||
}
|
||||
|
||||
func encodeSigHeader(w io.Writer, header *types.Header) {
|
||||
err := rlp.Encode(w, []interface{}{
|
||||
func encodeSigHeader(w io.Writer, header *types.Header, c *params.BorConfig) {
|
||||
enc := []interface{}{
|
||||
header.ParentHash,
|
||||
header.UncleHash,
|
||||
header.Coinbase,
|
||||
|
|
@ -172,8 +172,13 @@ func encodeSigHeader(w io.Writer, header *types.Header) {
|
|||
header.Extra[:len(header.Extra)-65], // Yes, this will panic if extra is too short
|
||||
header.MixDigest,
|
||||
header.Nonce,
|
||||
})
|
||||
if err != nil {
|
||||
}
|
||||
if c.IsJaipur(header.Number.Uint64()) {
|
||||
if header.BaseFee != nil {
|
||||
enc = append(enc, header.BaseFee)
|
||||
}
|
||||
}
|
||||
if err := rlp.Encode(w, enc); err != nil {
|
||||
panic("can't encode: " + err.Error())
|
||||
}
|
||||
}
|
||||
|
|
@ -199,9 +204,9 @@ func CalcProducerDelay(number uint64, succession int, c *params.BorConfig) uint6
|
|||
// Note, the method requires the extra data to be at least 65 bytes, otherwise it
|
||||
// panics. This is done to avoid accidentally using both forms (signature present
|
||||
// or not), which could be abused to produce different hashes for the same header.
|
||||
func BorRLP(header *types.Header) []byte {
|
||||
func BorRLP(header *types.Header, c *params.BorConfig) []byte {
|
||||
b := new(bytes.Buffer)
|
||||
encodeSigHeader(b, header)
|
||||
encodeSigHeader(b, header, c)
|
||||
return b.Bytes()
|
||||
}
|
||||
|
||||
|
|
@ -280,7 +285,7 @@ func New(
|
|||
// Author implements consensus.Engine, returning the Ethereum address recovered
|
||||
// from the signature in the header's extra-data section.
|
||||
func (c *Bor) Author(header *types.Header) (common.Address, error) {
|
||||
return ecrecover(header, c.signatures)
|
||||
return ecrecover(header, c.signatures, c.config)
|
||||
}
|
||||
|
||||
// VerifyHeader checks whether a header conforms to the consensus rules.
|
||||
|
|
@ -578,7 +583,7 @@ func (c *Bor) verifySeal(chain consensus.ChainHeaderReader, header *types.Header
|
|||
}
|
||||
|
||||
// Resolve the authorization key and check against signers
|
||||
signer, err := ecrecover(header, c.signatures)
|
||||
signer, err := ecrecover(header, c.signatures, c.config)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
@ -844,7 +849,7 @@ func (c *Bor) Seal(chain consensus.ChainHeaderReader, block *types.Block, result
|
|||
wiggle := time.Duration(successionNumber) * time.Duration(c.config.CalculateBackupMultiplier(number)) * time.Second
|
||||
|
||||
// Sign all the things!
|
||||
sighash, err := signFn(accounts.Account{Address: signer}, accounts.MimetypeBor, BorRLP(header))
|
||||
sighash, err := signFn(accounts.Account{Address: signer}, accounts.MimetypeBor, BorRLP(header, c.config))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
@ -876,7 +881,7 @@ func (c *Bor) Seal(chain consensus.ChainHeaderReader, block *types.Block, result
|
|||
select {
|
||||
case results <- block.WithSeal(header):
|
||||
default:
|
||||
log.Warn("Sealing result was not read by miner", "number", number, "sealhash", SealHash(header))
|
||||
log.Warn("Sealing result was not read by miner", "number", number, "sealhash", SealHash(header, c.config))
|
||||
}
|
||||
}()
|
||||
return nil
|
||||
|
|
@ -895,7 +900,7 @@ func (c *Bor) CalcDifficulty(chain consensus.ChainHeaderReader, time uint64, par
|
|||
|
||||
// SealHash returns the hash of a block prior to it being sealed.
|
||||
func (c *Bor) SealHash(header *types.Header) common.Hash {
|
||||
return SealHash(header)
|
||||
return SealHash(header, c.config)
|
||||
}
|
||||
|
||||
// APIs implements consensus.Engine, returning the user facing RPC API to allow
|
||||
|
|
|
|||
|
|
@ -99,3 +99,39 @@ func TestGenesisContractChange(t *testing.T) {
|
|||
// make sure balance change DOES NOT take effect
|
||||
assert.Equal(t, statedb.GetBalance(addr0), big.NewInt(0))
|
||||
}
|
||||
|
||||
func TestEncodeSigHeaderJaipur(t *testing.T) {
|
||||
// As part of the EIP-1559 fork in mumbai, an incorrect seal hash
|
||||
// was used for Bor that did not included the BaseFee. The Jaipur
|
||||
// block is a hard fork to fix that.
|
||||
h := &types.Header{
|
||||
Difficulty: new(big.Int),
|
||||
Number: big.NewInt(1),
|
||||
Extra: make([]byte, 32+65),
|
||||
}
|
||||
|
||||
var (
|
||||
// hash for the block without the BaseFee
|
||||
hashWithoutBaseFee = common.HexToHash("0x1be13e83939b3c4701ee57a34e10c9290ce07b0e53af0fe90b812c6881826e36")
|
||||
// hash for the block with the baseFee
|
||||
hashWithBaseFee = common.HexToHash("0xc55b0cac99161f71bde1423a091426b1b5b4d7598e5981ad802cce712771965b")
|
||||
)
|
||||
|
||||
// Jaipur NOT enabled and BaseFee not set
|
||||
hash := SealHash(h, ¶ms.BorConfig{JaipurBlock: 10})
|
||||
assert.Equal(t, hash, hashWithoutBaseFee)
|
||||
|
||||
// Jaipur enabled (Jaipur=0) and BaseFee not set
|
||||
hash = SealHash(h, ¶ms.BorConfig{JaipurBlock: 0})
|
||||
assert.Equal(t, hash, hashWithoutBaseFee)
|
||||
|
||||
h.BaseFee = big.NewInt(2)
|
||||
|
||||
// Jaipur enabled (Jaipur=Header block) and BaseFee set
|
||||
hash = SealHash(h, ¶ms.BorConfig{JaipurBlock: 1})
|
||||
assert.Equal(t, hash, hashWithBaseFee)
|
||||
|
||||
// Jaipur NOT enabled and BaseFee set
|
||||
hash = SealHash(h, ¶ms.BorConfig{JaipurBlock: 10})
|
||||
assert.Equal(t, hash, hashWithoutBaseFee)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -131,7 +131,7 @@ func (s *Snapshot) apply(headers []*types.Header) (*Snapshot, error) {
|
|||
}
|
||||
|
||||
// Resolve the authorization key and check against signers
|
||||
signer, err := ecrecover(header, s.sigcache)
|
||||
signer, err := ecrecover(header, s.sigcache, s.config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -276,6 +276,7 @@ var (
|
|||
BerlinBlock: big.NewInt(13996000),
|
||||
LondonBlock: big.NewInt(22640000),
|
||||
Bor: &BorConfig{
|
||||
JaipurBlock: 22770000,
|
||||
Period: map[string]uint64{
|
||||
"0": 2,
|
||||
},
|
||||
|
|
@ -486,7 +487,8 @@ type BorConfig struct {
|
|||
StateReceiverContract string `json:"stateReceiverContract"` // State receiver contract
|
||||
OverrideStateSyncRecords map[string]int `json:"overrideStateSyncRecords"` // override state records count
|
||||
BlockAlloc map[string]interface{} `json:"blockAlloc"`
|
||||
BurntContract map[string]string `json:"burntContract"` // governance contract where the token will be sent to and burnt in london fork
|
||||
BurntContract map[string]string `json:"burntContract"` // governance contract where the token will be sent to and burnt in london fork
|
||||
JaipurBlock uint64 `json:"jaipurBlock"` // Jaipur switch block (nil = no fork, 0 = already on jaipur)
|
||||
}
|
||||
|
||||
// String implements the stringer interface, returning the consensus engine details.
|
||||
|
|
@ -502,6 +504,10 @@ func (c *BorConfig) CalculatePeriod(number uint64) uint64 {
|
|||
return c.calculateBorConfigHelper(c.Period, number)
|
||||
}
|
||||
|
||||
func (c *BorConfig) IsJaipur(number uint64) bool {
|
||||
return number >= c.JaipurBlock
|
||||
}
|
||||
|
||||
func (c *BorConfig) calculateBorConfigHelper(field map[string]uint64, number uint64) uint64 {
|
||||
keys := make([]string, 0, len(field))
|
||||
for k := range field {
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ package bor
|
|||
import (
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"io"
|
||||
"math/big"
|
||||
"testing"
|
||||
"time"
|
||||
|
|
@ -16,9 +17,11 @@ import (
|
|||
"github.com/ethereum/go-ethereum/core/vm"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
"github.com/ethereum/go-ethereum/rlp"
|
||||
"github.com/ethereum/go-ethereum/tests/bor/mocks"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/mock"
|
||||
"golang.org/x/crypto/sha3"
|
||||
)
|
||||
|
||||
var (
|
||||
|
|
@ -192,7 +195,7 @@ func TestOutOfTurnSigning(t *testing.T) {
|
|||
header := block.Header()
|
||||
header.Time += (bor.CalcProducerDelay(header.Number.Uint64(), expectedSuccessionNumber, init.genesis.Config.Bor) -
|
||||
bor.CalcProducerDelay(header.Number.Uint64(), 0, init.genesis.Config.Bor))
|
||||
sign(t, header, signerKey)
|
||||
sign(t, header, signerKey, init.genesis.Config.Bor)
|
||||
block = types.NewBlockWithHeader(header)
|
||||
_, err = chain.InsertChain([]*types.Block{block})
|
||||
assert.Equal(t,
|
||||
|
|
@ -200,7 +203,7 @@ func TestOutOfTurnSigning(t *testing.T) {
|
|||
bor.WrongDifficultyError{Number: spanSize, Expected: expectedDifficulty, Actual: 3, Signer: addr.Bytes()})
|
||||
|
||||
header.Difficulty = new(big.Int).SetUint64(expectedDifficulty)
|
||||
sign(t, header, signerKey)
|
||||
sign(t, header, signerKey, init.genesis.Config.Bor)
|
||||
block = types.NewBlockWithHeader(header)
|
||||
_, err = chain.InsertChain([]*types.Block{block})
|
||||
assert.Nil(t, err)
|
||||
|
|
@ -502,3 +505,58 @@ func TestEIP1559Transition(t *testing.T) {
|
|||
func newGwei(n int64) *big.Int {
|
||||
return new(big.Int).Mul(big.NewInt(n), big.NewInt(params.GWei))
|
||||
}
|
||||
|
||||
func TestJaipurFork(t *testing.T) {
|
||||
init := buildEthereumInstance(t, rawdb.NewMemoryDatabase())
|
||||
chain := init.ethereum.BlockChain()
|
||||
engine := init.ethereum.Engine()
|
||||
_bor := engine.(*bor.Bor)
|
||||
db := init.ethereum.ChainDb()
|
||||
block := init.genesis.ToBlock(db)
|
||||
for i := uint64(1); i < sprintSize; i++ {
|
||||
block = buildNextBlock(t, _bor, chain, block, nil, init.genesis.Config.Bor)
|
||||
insertNewBlock(t, chain, block)
|
||||
if block.Number().Uint64() == init.genesis.Config.Bor.JaipurBlock-1 {
|
||||
assert.Equal(t, testSealHash(block.Header(), init.genesis.Config.Bor), bor.SealHash(block.Header(), init.genesis.Config.Bor))
|
||||
}
|
||||
if block.Number().Uint64() == init.genesis.Config.Bor.JaipurBlock {
|
||||
assert.Equal(t, testSealHash(block.Header(), init.genesis.Config.Bor), bor.SealHash(block.Header(), init.genesis.Config.Bor))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// SealHash returns the hash of a block prior to it being sealed.
|
||||
func testSealHash(header *types.Header, c *params.BorConfig) (hash common.Hash) {
|
||||
hasher := sha3.NewLegacyKeccak256()
|
||||
testEncodeSigHeader(hasher, header, c)
|
||||
hasher.Sum(hash[:0])
|
||||
return hash
|
||||
}
|
||||
|
||||
func testEncodeSigHeader(w io.Writer, header *types.Header, c *params.BorConfig) {
|
||||
enc := []interface{}{
|
||||
header.ParentHash,
|
||||
header.UncleHash,
|
||||
header.Coinbase,
|
||||
header.Root,
|
||||
header.TxHash,
|
||||
header.ReceiptHash,
|
||||
header.Bloom,
|
||||
header.Difficulty,
|
||||
header.Number,
|
||||
header.GasLimit,
|
||||
header.GasUsed,
|
||||
header.Time,
|
||||
header.Extra[:len(header.Extra)-65], // Yes, this will panic if extra is too short
|
||||
header.MixDigest,
|
||||
header.Nonce,
|
||||
}
|
||||
if c.IsJaipur(header.Number.Uint64()) {
|
||||
if header.BaseFee != nil {
|
||||
enc = append(enc, header.BaseFee)
|
||||
}
|
||||
}
|
||||
if err := rlp.Encode(w, enc); err != nil {
|
||||
panic("can't encode: " + err.Error())
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ import (
|
|||
"github.com/ethereum/go-ethereum/cmd/utils"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/consensus/bor"
|
||||
"github.com/ethereum/go-ethereum/consensus/misc"
|
||||
"github.com/ethereum/go-ethereum/core"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
|
|
@ -111,6 +112,14 @@ func buildNextBlock(t *testing.T, _bor *bor.Bor, chain *core.BlockChain, block *
|
|||
copy(header.Extra[32:], validatorBytes)
|
||||
}
|
||||
|
||||
if chain.Config().IsLondon(header.Number) {
|
||||
header.BaseFee = misc.CalcBaseFee(chain.Config(), block.Header())
|
||||
if !chain.Config().IsLondon(block.Number()) {
|
||||
parentGasLimit := block.GasLimit() * params.ElasticityMultiplier
|
||||
header.GasLimit = core.CalcGasLimit(parentGasLimit, parentGasLimit)
|
||||
}
|
||||
}
|
||||
|
||||
state, err := chain.State()
|
||||
if err != nil {
|
||||
t.Fatalf("%s", err)
|
||||
|
|
@ -119,12 +128,12 @@ func buildNextBlock(t *testing.T, _bor *bor.Bor, chain *core.BlockChain, block *
|
|||
if err != nil {
|
||||
t.Fatalf("%s", err)
|
||||
}
|
||||
sign(t, header, signer)
|
||||
sign(t, header, signer, borConfig)
|
||||
return types.NewBlockWithHeader(header)
|
||||
}
|
||||
|
||||
func sign(t *testing.T, header *types.Header, signer []byte) {
|
||||
sig, err := secp256k1.Sign(crypto.Keccak256(bor.BorRLP(header)), signer)
|
||||
func sign(t *testing.T, header *types.Header, signer []byte, c *params.BorConfig) {
|
||||
sig, err := secp256k1.Sign(crypto.Keccak256(bor.BorRLP(header, c)), signer)
|
||||
if err != nil {
|
||||
t.Fatalf("%s", err)
|
||||
}
|
||||
|
|
|
|||
3
tests/bor/testdata/genesis.json
vendored
3
tests/bor/testdata/genesis.json
vendored
|
|
@ -12,8 +12,9 @@
|
|||
"istanbulBlock": 0,
|
||||
"muirGlacierBlock": 0,
|
||||
"berlinBlock": 0,
|
||||
"londonBlock": 10,
|
||||
"londonBlock": 1,
|
||||
"bor": {
|
||||
"jaipurBlock": 2,
|
||||
"period": {
|
||||
"0": 1
|
||||
},
|
||||
|
|
|
|||
Loading…
Reference in a new issue