Merge pull request #294 from maticnetwork/v0.2.13-candidate

v0.2.13 candidate
This commit is contained in:
Sandeep Sreenath 2022-01-13 14:07:33 +05:30 committed by GitHub
commit 0978123079
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
16 changed files with 637 additions and 64 deletions

29
.github/workflows/dockerimage.yml vendored Normal file
View file

@ -0,0 +1,29 @@
name: Bor Docker Image CI
on:
push:
branches-ignore:
- '**'
tags:
- 'v*.*.*'
# to be used by fork patch-releases ^^
- 'v*.*.*-*'
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Build the Bor Docker image
env:
DOCKERHUB: ${{ secrets.DOCKERHUB }}
DOCKERHUB_KEY: ${{ secrets.DOCKERHUB_KEY }}
run: |
ls -l
echo "Docker login"
docker login -u $DOCKERHUB -p $DOCKERHUB_KEY
echo "running build"
docker build -f Dockerfile.classic -t maticnetwork/bor:${GITHUB_REF/refs\/tags\//} .
echo "pushing image"
docker push maticnetwork/bor:${GITHUB_REF/refs\/tags\//}
echo "DONE!"

18
Dockerfile.classic Normal file
View file

@ -0,0 +1,18 @@
# Build Geth in a stock Go builder container
FROM golang:1.17-alpine as builder
RUN apk add --no-cache make gcc musl-dev linux-headers git bash
ADD . /bor
RUN cd /bor && make bor-all
CMD ["/bin/bash"]
# Pull Bor into a second stage deploy alpine container
FROM alpine:latest
RUN apk add --no-cache ca-certificates
COPY --from=builder /bor/build/bin/bor /usr/local/bin/
COPY --from=builder /bor/build/bin/bootnode /usr/local/bin/
EXPOSE 8545 8546 8547 30303 30303/udp

View file

@ -50,8 +50,8 @@ ios:
test: all
# $(GORUN) build/ci.go test
go test github.com/ethereum/go-ethereum/consensus/bor
go test github.com/ethereum/go-ethereum/tests/bor
go test github.com/ethereum/go-ethereum/consensus/bor -v
go test github.com/ethereum/go-ethereum/tests/bor -v
lint: ## Run linters.
$(GORUN) build/ci.go lint

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -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())
}
}
@ -182,12 +187,12 @@ func encodeSigHeader(w io.Writer, header *types.Header) {
func CalcProducerDelay(number uint64, succession int, c *params.BorConfig) uint64 {
// When the block is the first block of the sprint, it is expected to be delayed by `producerDelay`.
// That is to allow time for block propagation in the last sprint
delay := c.Period
delay := c.CalculatePeriod(number)
if number%c.Sprint == 0 {
delay = c.ProducerDelay
}
if succession > 0 {
delay += uint64(succession) * c.BackupMultiplier
delay += uint64(succession) * c.CalculateBackupMultiplier(number)
}
return delay
}
@ -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.
@ -353,6 +358,11 @@ func (c *Bor) verifyHeader(chain consensus.ChainHeaderReader, header *types.Head
return errInvalidDifficulty
}
}
// Verify that the gas limit is <= 2^63-1
cap := uint64(0x7fffffffffffffff)
if header.GasLimit > cap {
return fmt.Errorf("invalid gasLimit: have %v, max %v", header.GasLimit, cap)
}
// If all checks passed, validate any special fields for hard forks
if err := misc.VerifyForkHashes(chain.Config(), header, false); err != nil {
return err
@ -396,7 +406,24 @@ func (c *Bor) verifyCascadingFields(chain consensus.ChainHeaderReader, header *t
return consensus.ErrUnknownAncestor
}
if parent.Time+c.config.Period > header.Time {
// Verify that the gasUsed is <= gasLimit
if header.GasUsed > header.GasLimit {
return fmt.Errorf("invalid gasUsed: have %d, gasLimit %d", header.GasUsed, header.GasLimit)
}
if !chain.Config().IsLondon(header.Number) {
// Verify BaseFee not present before EIP-1559 fork.
if header.BaseFee != nil {
return fmt.Errorf("invalid baseFee before fork: have %d, want <nil>", header.BaseFee)
}
if err := misc.VerifyGaslimit(parent.GasLimit, header.GasLimit); err != nil {
return err
}
} else if err := misc.VerifyEip1559Header(chain.Config(), parent, header); err != nil {
// Verify the header's EIP-1559 attributes.
return err
}
if parent.Time+c.config.CalculatePeriod(number) > header.Time {
return ErrInvalidTimestamp
}
@ -556,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
}
@ -791,7 +818,7 @@ func (c *Bor) Seal(chain consensus.ChainHeaderReader, block *types.Block, result
return errUnknownBlock
}
// For 0-period chains, refuse to seal empty blocks (no reward but would spin sealing)
if c.config.Period == 0 && len(block.Transactions()) == 0 {
if c.config.CalculatePeriod(number) == 0 && len(block.Transactions()) == 0 {
log.Info("Sealing paused, waiting for transactions")
return nil
}
@ -819,10 +846,10 @@ func (c *Bor) Seal(chain consensus.ChainHeaderReader, block *types.Block, result
// Sweet, the protocol permits us to sign the block, wait for our time
delay := time.Unix(int64(header.Time), 0).Sub(time.Now()) // nolint: gosimple
// wiggle was already accounted for in header.Time, this is just for logging
wiggle := time.Duration(successionNumber) * time.Duration(c.config.BackupMultiplier) * time.Second
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
}
@ -854,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
@ -873,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

View file

@ -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, &params.BorConfig{JaipurBlock: 10})
assert.Equal(t, hash, hashWithoutBaseFee)
// Jaipur enabled (Jaipur=0) and BaseFee not set
hash = SealHash(h, &params.BorConfig{JaipurBlock: 0})
assert.Equal(t, hash, hashWithoutBaseFee)
h.BaseFee = big.NewInt(2)
// Jaipur enabled (Jaipur=Header block) and BaseFee set
hash = SealHash(h, &params.BorConfig{JaipurBlock: 1})
assert.Equal(t, hash, hashWithBaseFee)
// Jaipur NOT enabled and BaseFee set
hash = SealHash(h, &params.BorConfig{JaipurBlock: 10})
assert.Equal(t, hash, hashWithoutBaseFee)
}

View file

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

View file

@ -337,6 +337,11 @@ func (st *StateTransition) TransitionDb() (*ExecutionResult, error) {
effectiveTip = cmath.BigMin(st.gasTipCap, new(big.Int).Sub(st.gasFeeCap, st.evm.Context.BaseFee))
}
amount := new(big.Int).Mul(new(big.Int).SetUint64(st.gasUsed()), effectiveTip)
if london {
burntContractAddress := common.HexToAddress(st.evm.ChainConfig().Bor.CalculateBurntContract(st.evm.Context.BlockNumber.Uint64()))
burnAmount := new(big.Int).Mul(new(big.Int).SetUint64(st.gasUsed()), st.evm.Context.BaseFee)
st.state.AddBalance(burntContractAddress, burnAmount)
}
st.state.AddBalance(st.evm.Context.Coinbase, amount)
output1 := new(big.Int).SetBytes(input1.Bytes())
output2 := new(big.Int).SetBytes(input2.Bytes())

View file

@ -31,7 +31,7 @@ func (s *PublicBlockChainAPI) appendRPCMarshalBorTransaction(ctx context.Context
if borTx != nil {
formattedTxs := fields["transactions"].([]interface{})
if fullTx {
marshalledTx := newRPCTransaction(borTx, blockHash, blockNumber, txIndex, nil, s.b.ChainConfig())
marshalledTx := newRPCTransaction(borTx, blockHash, blockNumber, txIndex, block.BaseFee(), s.b.ChainConfig())
// newRPCTransaction calculates hash based on RLP of the transaction data.
// In case of bor block tx, we need simple derived tx hash (same as function argument) instead of RLP hash
marshalledTx.Hash = txHash

View file

@ -20,6 +20,8 @@ import (
"encoding/binary"
"fmt"
"math/big"
"sort"
"strconv"
"github.com/ethereum/go-ethereum/common"
"golang.org/x/crypto/sha3"
@ -222,6 +224,40 @@ var (
Threshold: 2,
}
// BorTestChainConfig contains the chain parameters to run a node on the Test network.
BorTestChainConfig = &ChainConfig{
ChainID: big.NewInt(80001),
HomesteadBlock: big.NewInt(0),
DAOForkBlock: nil,
DAOForkSupport: true,
EIP150Hash: common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000000"),
EIP150Block: big.NewInt(0),
EIP155Block: big.NewInt(0),
EIP158Block: big.NewInt(0),
ByzantiumBlock: big.NewInt(0),
ConstantinopleBlock: big.NewInt(0),
PetersburgBlock: big.NewInt(0),
IstanbulBlock: big.NewInt(0),
MuirGlacierBlock: big.NewInt(0),
BerlinBlock: big.NewInt(0),
LondonBlock: big.NewInt(0),
Bor: &BorConfig{
Period: map[string]uint64{
"0": 2,
},
ProducerDelay: 6,
Sprint: 64,
BackupMultiplier: map[string]uint64{
"0": 2,
},
ValidatorContract: "0x0000000000000000000000000000000000001000",
StateReceiverContract: "0x0000000000000000000000000000000000001001",
BurntContract: map[string]string{
"0": "0x00000000000000000000000000000000000000000",
},
},
}
// MumbaiChainConfig contains the chain parameters to run a node on the Mumbai test network.
MumbaiChainConfig = &ChainConfig{
ChainID: big.NewInt(80001),
@ -238,13 +274,22 @@ var (
IstanbulBlock: big.NewInt(2722000),
MuirGlacierBlock: big.NewInt(2722000),
BerlinBlock: big.NewInt(13996000),
LondonBlock: big.NewInt(22640000),
Bor: &BorConfig{
Period: 2,
ProducerDelay: 6,
Sprint: 64,
BackupMultiplier: 2,
JaipurBlock: 22770000,
Period: map[string]uint64{
"0": 2,
},
ProducerDelay: 6,
Sprint: 64,
BackupMultiplier: map[string]uint64{
"0": 2,
},
ValidatorContract: "0x0000000000000000000000000000000000001000",
StateReceiverContract: "0x0000000000000000000000000000000000001001",
BurntContract: map[string]string{
"22640000": "0x70bcA57F4579f58670aB2d18Ef16e02C17553C38",
},
BlockAlloc: map[string]interface{}{
// write as interface since that is how it is decoded in genesis
"22244000": map[string]interface{}{
@ -272,11 +317,17 @@ var (
IstanbulBlock: big.NewInt(3395000),
MuirGlacierBlock: big.NewInt(3395000),
BerlinBlock: big.NewInt(14750000),
LondonBlock: big.NewInt(23850000),
Bor: &BorConfig{
Period: 2,
ProducerDelay: 6,
Sprint: 64,
BackupMultiplier: 2,
JaipurBlock: 23850000,
Period: map[string]uint64{
"0": 2,
},
ProducerDelay: 6,
Sprint: 64,
BackupMultiplier: map[string]uint64{
"0": 2,
},
ValidatorContract: "0x0000000000000000000000000000000000001000",
StateReceiverContract: "0x0000000000000000000000000000000000001001",
OverrideStateSyncRecords: map[string]int{
@ -290,6 +341,9 @@ var (
"14953792": 0,
"14953856": 0,
},
BurntContract: map[string]string{
"23850000": "0x70bca57f4579f58670ab2d18ef16e02c17553c38",
},
BlockAlloc: map[string]interface{}{
// write as interface since that is how it is decoded in genesis
"22156660": map[string]interface{}{
@ -426,15 +480,16 @@ func (c *CliqueConfig) String() string {
// BorConfig is the consensus engine configs for Matic bor based sealing.
type BorConfig struct {
Period uint64 `json:"period"` // Number of seconds between blocks to enforce
ProducerDelay uint64 `json:"producerDelay"` // Number of seconds delay between two producer interval
Sprint uint64 `json:"sprint"` // Epoch length to proposer
BackupMultiplier uint64 `json:"backupMultiplier"` // Backup multiplier to determine the wiggle time
ValidatorContract string `json:"validatorContract"` // Validator set contract
StateReceiverContract string `json:"stateReceiverContract"` // State receiver contract
Period map[string]uint64 `json:"period"` // Number of seconds between blocks to enforce
ProducerDelay uint64 `json:"producerDelay"` // Number of seconds delay between two producer interval
Sprint uint64 `json:"sprint"` // Epoch length to proposer
BackupMultiplier map[string]uint64 `json:"backupMultiplier"` // Backup multiplier to determine the wiggle time
ValidatorContract string `json:"validatorContract"` // Validator set contract
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
JaipurBlock uint64 `json:"jaipurBlock"` // Jaipur switch block (nil = no fork, 0 = already on jaipur)
}
// String implements the stringer interface, returning the consensus engine details.
@ -442,6 +497,50 @@ func (b *BorConfig) String() string {
return "bor"
}
func (c *BorConfig) CalculateBackupMultiplier(number uint64) uint64 {
return c.calculateBorConfigHelper(c.BackupMultiplier, number)
}
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 {
keys = append(keys, k)
}
sort.Strings(keys)
for i := 0; i < len(keys)-1; i++ {
valUint, _ := strconv.ParseUint(keys[i], 10, 64)
valUintNext, _ := strconv.ParseUint(keys[i+1], 10, 64)
if number > valUint && number < valUintNext {
return field[keys[i]]
}
}
return field[keys[len(keys)-1]]
}
func (c *BorConfig) CalculateBurntContract(number uint64) string {
keys := make([]string, 0, len(c.BurntContract))
for k := range c.BurntContract {
keys = append(keys, k)
}
sort.Strings(keys)
for i := 0; i < len(keys)-1; i++ {
valUint, _ := strconv.ParseUint(keys[i], 10, 64)
valUintNext, _ := strconv.ParseUint(keys[i+1], 10, 64)
if number > valUint && number < valUintNext {
return c.BurntContract[keys[i]]
}
}
return c.BurntContract[keys[len(keys)-1]]
}
// String implements the fmt.Stringer interface.
func (c *ChainConfig) String() string {
var engine interface{}

View file

@ -21,9 +21,9 @@ import (
)
const (
VersionMajor = 0 // Major version component of the current release
VersionMinor = 2 // Minor version component of the current release
VersionPatch = 12 // Patch version component of the current release
VersionMajor = 0 // Major version component of the current release
VersionMinor = 2 // Minor version component of the current release
VersionPatch = 13 // Patch version component of the current release
VersionMeta = "stable" // Version metadata to append to the version string
)

View file

@ -3,18 +3,25 @@ package bor
import (
"encoding/hex"
"encoding/json"
"io"
"math/big"
"testing"
"time"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/consensus/bor"
"github.com/ethereum/go-ethereum/consensus/ethash"
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/types"
"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 (
@ -188,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,
@ -196,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)
@ -268,3 +275,288 @@ func getSampleEventRecord(t *testing.T) *bor.EventRecordWithTime {
_eventRecords[0].Time = time.Unix(1, 0)
return _eventRecords[0]
}
// TestEIP1559Transition tests the following:
//
// 1. A transaction whose gasFeeCap is greater than the baseFee is valid.
// 2. Gas accounting for access lists on EIP-1559 transactions is correct.
// 3. Only the transaction's tip will be received by the coinbase.
// 4. The transaction sender pays for both the tip and baseFee.
// 5. The coinbase receives only the partially realized tip when
// gasFeeCap - gasTipCap < baseFee.
// 6. Legacy transaction behave as expected (e.g. gasPrice = gasFeeCap = gasTipCap).
func TestEIP1559Transition(t *testing.T) {
var (
aa = common.HexToAddress("0x000000000000000000000000000000000000aaaa")
// Generate a canonical chain to act as the main dataset
db = rawdb.NewMemoryDatabase()
engine = ethash.NewFaker()
// A sender who makes transactions, has some funds
key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
key2, _ = crypto.HexToECDSA("8a1f9a8f95be41cd7ccb6168179afb4504aefe388d1e14474d32c45c72ce7b7a")
key3, _ = crypto.HexToECDSA("225171aed3793cba1c029832886d69785b7e77a54a44211226b447aa2d16b058")
addr1 = crypto.PubkeyToAddress(key1.PublicKey)
addr2 = crypto.PubkeyToAddress(key2.PublicKey)
addr3 = crypto.PubkeyToAddress(key3.PublicKey)
funds = new(big.Int).Mul(common.Big1, big.NewInt(params.Ether))
gspec = &core.Genesis{
Config: params.BorTestChainConfig,
Alloc: core.GenesisAlloc{
addr1: {Balance: funds},
addr2: {Balance: funds},
addr3: {Balance: funds},
// The address 0xAAAA sloads 0x00 and 0x01
aa: {
Code: []byte{
byte(vm.PC),
byte(vm.PC),
byte(vm.SLOAD),
byte(vm.SLOAD),
},
Nonce: 0,
Balance: big.NewInt(0),
},
},
}
)
gspec.Config.BerlinBlock = common.Big0
gspec.Config.LondonBlock = common.Big0
genesis := gspec.MustCommit(db)
signer := types.LatestSigner(gspec.Config)
blocks, _ := core.GenerateChain(gspec.Config, genesis, engine, db, 1, func(i int, b *core.BlockGen) {
b.SetCoinbase(common.Address{1})
// One transaction to 0xAAAA
accesses := types.AccessList{types.AccessTuple{
Address: aa,
StorageKeys: []common.Hash{{0}},
}}
txdata := &types.DynamicFeeTx{
ChainID: gspec.Config.ChainID,
Nonce: 0,
To: &aa,
Gas: 30000,
GasFeeCap: newGwei(5),
GasTipCap: big.NewInt(2),
AccessList: accesses,
Data: []byte{},
}
tx := types.NewTx(txdata)
tx, _ = types.SignTx(tx, signer, key1)
b.AddTx(tx)
})
diskdb := rawdb.NewMemoryDatabase()
gspec.MustCommit(diskdb)
chain, err := core.NewBlockChain(diskdb, nil, gspec.Config, engine, vm.Config{}, nil, nil)
if err != nil {
t.Fatalf("failed to create tester chain: %v", err)
}
if n, err := chain.InsertChain(blocks); err != nil {
t.Fatalf("block %d: failed to insert into chain: %v", n, err)
}
block := chain.GetBlockByNumber(1)
// 1+2: Ensure EIP-1559 access lists are accounted for via gas usage.
expectedGas := params.TxGas + params.TxAccessListAddressGas + params.TxAccessListStorageKeyGas +
vm.GasQuickStep*2 + params.WarmStorageReadCostEIP2929 + params.ColdSloadCostEIP2929
if block.GasUsed() != expectedGas {
t.Fatalf("incorrect amount of gas spent: expected %d, got %d", expectedGas, block.GasUsed())
}
state, _ := chain.State()
// 3: Ensure that miner received only the tx's tip.
actual := state.GetBalance(block.Coinbase())
expected := new(big.Int).Add(
new(big.Int).SetUint64(block.GasUsed()*block.Transactions()[0].GasTipCap().Uint64()),
ethash.ConstantinopleBlockReward,
)
if actual.Cmp(expected) != 0 {
t.Fatalf("miner balance incorrect: expected %d, got %d", expected, actual)
}
// check burnt contract balance
actual = state.GetBalance(common.HexToAddress(params.BorTestChainConfig.Bor.CalculateBurntContract(block.NumberU64())))
expected = new(big.Int).Mul(new(big.Int).SetUint64(block.GasUsed()), block.BaseFee())
burntContractBalance := expected
if actual.Cmp(expected) != 0 {
t.Fatalf("burnt contract balance incorrect: expected %d, got %d", expected, actual)
}
// 4: Ensure the tx sender paid for the gasUsed * (tip + block baseFee).
actual = new(big.Int).Sub(funds, state.GetBalance(addr1))
expected = new(big.Int).SetUint64(block.GasUsed() * (block.Transactions()[0].GasTipCap().Uint64() + block.BaseFee().Uint64()))
if actual.Cmp(expected) != 0 {
t.Fatalf("sender balance incorrect: expected %d, got %d", expected, actual)
}
blocks, _ = core.GenerateChain(gspec.Config, block, engine, db, 1, func(i int, b *core.BlockGen) {
b.SetCoinbase(common.Address{2})
txdata := &types.LegacyTx{
Nonce: 0,
To: &aa,
Gas: 30000,
GasPrice: newGwei(5),
}
tx := types.NewTx(txdata)
tx, _ = types.SignTx(tx, signer, key2)
b.AddTx(tx)
})
if n, err := chain.InsertChain(blocks); err != nil {
t.Fatalf("block %d: failed to insert into chain: %v", n, err)
}
block = chain.GetBlockByNumber(2)
state, _ = chain.State()
effectiveTip := block.Transactions()[0].GasTipCap().Uint64() - block.BaseFee().Uint64()
// 6+5: Ensure that miner received only the tx's effective tip.
actual = state.GetBalance(block.Coinbase())
expected = new(big.Int).Add(
new(big.Int).SetUint64(block.GasUsed()*effectiveTip),
ethash.ConstantinopleBlockReward,
)
if actual.Cmp(expected) != 0 {
t.Fatalf("miner balance incorrect: expected %d, got %d", expected, actual)
}
// check burnt contract balance
actual = state.GetBalance(common.HexToAddress(params.BorTestChainConfig.Bor.CalculateBurntContract(block.NumberU64())))
expected = new(big.Int).Add(burntContractBalance, new(big.Int).Mul(new(big.Int).SetUint64(block.GasUsed()), block.BaseFee()))
burntContractBalance = expected
if actual.Cmp(expected) != 0 {
t.Fatalf("burnt contract balance incorrect: expected %d, got %d", expected, actual)
}
// 4: Ensure the tx sender paid for the gasUsed * (effectiveTip + block baseFee).
actual = new(big.Int).Sub(funds, state.GetBalance(addr2))
expected = new(big.Int).SetUint64(block.GasUsed() * (effectiveTip + block.BaseFee().Uint64()))
if actual.Cmp(expected) != 0 {
t.Fatalf("sender balance incorrect: expected %d, got %d", expected, actual)
}
blocks, _ = core.GenerateChain(gspec.Config, block, engine, db, 1, func(i int, b *core.BlockGen) {
b.SetCoinbase(common.Address{3})
txdata := &types.LegacyTx{
Nonce: 0,
To: &aa,
Gas: 30000,
GasPrice: newGwei(5),
}
tx := types.NewTx(txdata)
tx, _ = types.SignTx(tx, signer, key3)
b.AddTx(tx)
accesses := types.AccessList{types.AccessTuple{
Address: aa,
StorageKeys: []common.Hash{{0}},
}}
txdata2 := &types.DynamicFeeTx{
ChainID: gspec.Config.ChainID,
Nonce: 1,
To: &aa,
Gas: 30000,
GasFeeCap: newGwei(5),
GasTipCap: big.NewInt(2),
AccessList: accesses,
Data: []byte{},
}
tx = types.NewTx(txdata2)
tx, _ = types.SignTx(tx, signer, key3)
b.AddTx(tx)
})
if n, err := chain.InsertChain(blocks); err != nil {
t.Fatalf("block %d: failed to insert into chain: %v", n, err)
}
block = chain.GetBlockByNumber(3)
state, _ = chain.State()
// check burnt contract balance
actual = state.GetBalance(common.HexToAddress(params.BorTestChainConfig.Bor.CalculateBurntContract(block.NumberU64())))
burntAmount := new(big.Int).Mul(
block.BaseFee(),
big.NewInt(int64(block.GasUsed())),
)
expected = new(big.Int).Add(burntContractBalance, burntAmount)
if actual.Cmp(expected) != 0 {
t.Fatalf("burnt contract balance incorrect: expected %d, got %d", expected, actual)
}
}
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())
}
}

View file

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

View file

@ -8,13 +8,26 @@
"eip158Block": 0,
"byzantiumBlock": 0,
"constantinopleBlock": 0,
"petersburgBlock": 0,
"istanbulBlock": 0,
"muirGlacierBlock": 0,
"berlinBlock": 0,
"londonBlock": 1,
"bor": {
"period": 1,
"jaipurBlock": 2,
"period": {
"0": 1
},
"producerDelay": 4,
"sprint": 4,
"backupMultiplier": 1,
"backupMultiplier": {
"0": 1
},
"validatorContract": "0x0000000000000000000000000000000000001000",
"stateReceiverContract": "0x0000000000000000000000000000000000001001"
"stateReceiverContract": "0x0000000000000000000000000000000000001001",
"burntContract": {
"0": "0x0000000000000000000000000000000000000000"
}
}
},
"nonce": "0x0",