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

Metropolis aggregate PR #14726

Closed
wants to merge 6 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
81 changes: 69 additions & 12 deletions consensus/ethash/consensus.go
Original file line number Diff line number Diff line change
Expand Up @@ -287,8 +287,10 @@ func (ethash *Ethash) verifyHeader(chain consensus.ChainReader, header, parent *
// given the parent block's time and difficulty.
// TODO (karalabe): Move the chain maker into this package and make this private!
func CalcDifficulty(config *params.ChainConfig, time uint64, parent *types.Header) *big.Int {
next := new(big.Int).Add(parent.Number, common.Big1)
next := new(big.Int).Add(parent.Number, big1)
switch {
case config.IsMetropolis(next):
return calcDifficultyMetropolis(time, parent)
case config.IsHomestead(next):
return calcDifficultyHomestead(time, parent)
default:
Expand All @@ -299,10 +301,65 @@ func CalcDifficulty(config *params.ChainConfig, time uint64, parent *types.Heade
// Some weird constants to avoid constant memory allocs for them.
var (
expDiffPeriod = big.NewInt(100000)
big1 = big.NewInt(1)
big2 = big.NewInt(2)
big9 = big.NewInt(9)
big10 = big.NewInt(10)
bigMinus99 = big.NewInt(-99)
)

// calcDifficultyMetropolis is the difficulty adjustment algorithm. It returns
// the difficulty that a new block should have when created at time given the
// parent block's time and difficulty. The calculation uses the Metropolis rules.
func calcDifficultyMetropolis(time uint64, parent *types.Header) *big.Int {
// https://github.com/ethereum/EIPs/issues/100.
// algorithm:
// diff = (parent_diff +
// (parent_diff / 2048 * max((2 if len(parent.uncles) else 1) - ((timestamp - parent.timestamp) // 9), -99))
// ) + 2^(periodCount - 2)

bigTime := new(big.Int).SetUint64(time)
bigParentTime := new(big.Int).Set(parent.Time)

// holds intermediate values to make the algo easier to read & audit
x := new(big.Int)
y := new(big.Int)

// (2 if len(parent_uncles) else 1) - (block_timestamp - parent_timestamp) // 9
x.Sub(bigTime, bigParentTime)
x.Div(x, big9)
if parent.UncleHash == types.EmptyUncleHash {
x.Sub(big1, x)
} else {
x.Sub(big2, x)
}
// max((2 if len(parent_uncles) else 1) - (block_timestamp - parent_timestamp) // 9, -99)
if x.Cmp(bigMinus99) < 0 {
x.Set(bigMinus99)
}
// (parent_diff + parent_diff // 2048 * max(1 - (block_timestamp - parent_timestamp) // 10, -99))
y.Div(parent.Difficulty, params.DifficultyBoundDivisor)
x.Mul(y, x)
x.Add(parent.Difficulty, x)

// minimum difficulty can ever be (before exponential factor)
if x.Cmp(params.MinimumDifficulty) < 0 {
x.Set(params.MinimumDifficulty)
}
// for the exponential factor
periodCount := new(big.Int).Add(parent.Number, big1)
periodCount.Div(periodCount, expDiffPeriod)

// the exponential factor, commonly referred to as "the bomb"
// diff = diff + 2^(periodCount - 2)
if periodCount.Cmp(big1) > 0 {
y.Sub(periodCount, big2)
y.Exp(big2, y, nil)
x.Add(x, y)
}
return x
}

// calcDifficultyHomestead is the difficulty adjustment algorithm. It returns
// the difficulty that a new block should have when created at time given the
// parent block's time and difficulty. The calculation uses the Homestead rules.
Expand All @@ -320,12 +377,12 @@ func calcDifficultyHomestead(time uint64, parent *types.Header) *big.Int {
x := new(big.Int)
y := new(big.Int)

// 1 - (block_timestamp -parent_timestamp) // 10
// 1 - (block_timestamp - parent_timestamp) // 10
x.Sub(bigTime, bigParentTime)
x.Div(x, big10)
x.Sub(common.Big1, x)
x.Sub(big1, x)

// max(1 - (block_timestamp - parent_timestamp) // 10, -99)))
// max(1 - (block_timestamp - parent_timestamp) // 10, -99)
if x.Cmp(bigMinus99) < 0 {
x.Set(bigMinus99)
}
Expand All @@ -339,14 +396,14 @@ func calcDifficultyHomestead(time uint64, parent *types.Header) *big.Int {
x.Set(params.MinimumDifficulty)
}
// for the exponential factor
periodCount := new(big.Int).Add(parent.Number, common.Big1)
periodCount := new(big.Int).Add(parent.Number, big1)
periodCount.Div(periodCount, expDiffPeriod)

// the exponential factor, commonly referred to as "the bomb"
// diff = diff + 2^(periodCount - 2)
if periodCount.Cmp(common.Big1) > 0 {
y.Sub(periodCount, common.Big2)
y.Exp(common.Big2, y, nil)
if periodCount.Cmp(big1) > 0 {
y.Sub(periodCount, big2)
y.Exp(big2, y, nil)
x.Add(x, y)
}
return x
Expand All @@ -373,12 +430,12 @@ func calcDifficultyFrontier(time uint64, parent *types.Header) *big.Int {
diff.Set(params.MinimumDifficulty)
}

periodCount := new(big.Int).Add(parent.Number, common.Big1)
periodCount := new(big.Int).Add(parent.Number, big1)
periodCount.Div(periodCount, expDiffPeriod)
if periodCount.Cmp(common.Big1) > 0 {
if periodCount.Cmp(big1) > 0 {
// diff = diff + 2^(periodCount - 2)
expDiff := periodCount.Sub(periodCount, common.Big2)
expDiff.Exp(common.Big2, expDiff, nil)
expDiff := periodCount.Sub(periodCount, big2)
expDiff.Exp(big2, expDiff, nil)
diff.Add(diff, expDiff)
diff = math.BigMax(diff, params.MinimumDifficulty)
}
Expand Down
1 change: 1 addition & 0 deletions core/chain_makers.go
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,7 @@ func makeHeader(config *params.ChainConfig, parent *types.Block, state *state.St
Number: parent.Number(),
Time: new(big.Int).Sub(time, big.NewInt(10)),
Difficulty: parent.Difficulty(),
UncleHash: parent.UncleHash(),
}),
GasLimit: CalcGasLimit(parent),
GasUsed: new(big.Int),
Expand Down
9 changes: 7 additions & 2 deletions core/state_processor.go
Original file line number Diff line number Diff line change
Expand Up @@ -105,10 +105,15 @@ func ApplyTransaction(config *params.ChainConfig, bc *BlockChain, author *common

// Update the state with pending changes
usedGas.Add(usedGas, gas)
var root []byte
if config.IsMetropolis(header.Number) {
statedb.Finalise()
} else {
root = statedb.IntermediateRoot(config.IsEIP158(header.Number)).Bytes()
}
// Create a new receipt for the transaction, storing the intermediate root and gas used by the tx
// based on the eip phase, we're passing wether the root touch-delete accounts.
root := statedb.IntermediateRoot(config.IsEIP158(header.Number))
receipt := types.NewReceipt(root.Bytes(), usedGas)
receipt := types.NewReceipt(root, usedGas)
receipt.TxHash = tx.Hash()
receipt.GasUsed = new(big.Int).Set(gas)
// if the transaction created a contract, store the creation address in the receipt.
Expand Down
3 changes: 2 additions & 1 deletion core/state_transition.go
Original file line number Diff line number Diff line change
Expand Up @@ -236,7 +236,8 @@ func (st *StateTransition) TransitionDb() (ret []byte, requiredGas, usedGas *big
vmerr error
)
if contractCreation {
ret, _, st.gas, vmerr = evm.Create(sender, st.data, st.gas, st.value)
createAddressFn := vm.CreateAddressFn(st.evm.ChainConfig(), st.evm.BlockNumber, sender.Address(), st.state.GetNonce(sender.Address()), st.data)
ret, _, st.gas, vmerr = evm.Create(sender, createAddressFn, st.data, st.gas, st.value)
} else {
// Increment the nonce for the next transaction
st.state.SetNonce(sender.Address(), st.state.GetNonce(sender.Address())+1)
Expand Down
9 changes: 4 additions & 5 deletions core/types/gen_receipt_json.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

40 changes: 29 additions & 11 deletions core/types/receipt.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ import (
// Receipt represents the results of a transaction.
type Receipt struct {
// Consensus fields
PostState []byte `json:"root" gencodec:"required"`
PostState []byte `json:"root"`
CumulativeGasUsed *big.Int `json:"cumulativeGasUsed" gencodec:"required"`
Bloom Bloom `json:"logsBloom" gencodec:"required"`
Logs []*Log `json:"logs" gencodec:"required"`
Expand All @@ -48,6 +48,19 @@ type receiptMarshaling struct {
GasUsed *hexutil.Big
}

type homesteadReceiptRLP struct {
PostState []byte
CumulativeGasUsed *big.Int
Bloom Bloom
Logs []*Log
}

type metropolisReceiptRLP struct {
CumulativeGasUsed *big.Int
Bloom Bloom
Logs []*Log
}

// NewReceipt creates a barebone transaction receipt, copying the init fields.
func NewReceipt(root []byte, cumulativeGasUsed *big.Int) *Receipt {
return &Receipt{PostState: common.CopyBytes(root), CumulativeGasUsed: new(big.Int).Set(cumulativeGasUsed)}
Expand All @@ -56,23 +69,28 @@ func NewReceipt(root []byte, cumulativeGasUsed *big.Int) *Receipt {
// EncodeRLP implements rlp.Encoder, and flattens the consensus fields of a receipt
// into an RLP stream.
func (r *Receipt) EncodeRLP(w io.Writer) error {
return rlp.Encode(w, []interface{}{r.PostState, r.CumulativeGasUsed, r.Bloom, r.Logs})
if r.PostState == nil {
return rlp.Encode(w, &metropolisReceiptRLP{r.CumulativeGasUsed, r.Bloom, r.Logs})
} else {
return rlp.Encode(w, &homesteadReceiptRLP{r.PostState, r.CumulativeGasUsed, r.Bloom, r.Logs})
}
}

// DecodeRLP implements rlp.Decoder, and loads the consensus fields of a receipt
// from an RLP stream.
func (r *Receipt) DecodeRLP(s *rlp.Stream) error {
var receipt struct {
PostState []byte
CumulativeGasUsed *big.Int
Bloom Bloom
Logs []*Log
}
if err := s.Decode(&receipt); err != nil {
raw, err := s.Raw()
if err != nil {
return err
}
r.PostState, r.CumulativeGasUsed, r.Bloom, r.Logs = receipt.PostState, receipt.CumulativeGasUsed, receipt.Bloom, receipt.Logs
return nil
var hr homesteadReceiptRLP
var mr metropolisReceiptRLP
if err = rlp.DecodeBytes(raw, &mr); err == nil {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will be active immediately. Is there a possibility that an attacker can insert a metro-receipt before metro is active?

r.CumulativeGasUsed, r.Bloom, r.Logs = mr.CumulativeGasUsed, mr.Bloom, mr.Logs
} else if err = rlp.DecodeBytes(raw, &hr); err == nil {
r.PostState, r.CumulativeGasUsed, r.Bloom, r.Logs = hr.PostState[:], hr.CumulativeGasUsed, hr.Bloom, hr.Logs
}
return err
}

// String implements the Stringer interface.
Expand Down
37 changes: 37 additions & 0 deletions core/types/transaction_signing.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@ type sigCache struct {
func MakeSigner(config *params.ChainConfig, blockNumber *big.Int) Signer {
var signer Signer
switch {
case config.IsMetropolis(blockNumber):
signer = NewEIP86Signer(config.ChainId)
case config.IsEIP155(blockNumber):
signer = NewEIP155Signer(config.ChainId)
case config.IsHomestead(blockNumber):
Expand Down Expand Up @@ -88,6 +90,10 @@ func Sender(signer Signer, tx *Transaction) (common.Address, error) {

pubkey, err := signer.PublicKey(tx)
if err != nil {
if err == errAbstractSigner {
return abstractSignerAddress, nil
}

return common.Address{}, err
}
var addr common.Address
Expand All @@ -108,6 +114,37 @@ type Signer interface {
Equal(Signer) bool
}

// EIP86Signer implements the the abstract signing feature
type EIP86Signer struct {
EIP155Signer
}

func NewEIP86Signer(chainId *big.Int) EIP86Signer {
return EIP86Signer{
EIP155Signer: NewEIP155Signer(chainId),
}
}

func (s EIP86Signer) Equal(s2 Signer) bool {
_, ok := s2.(EIP86Signer)
return ok && s.EIP155Signer.Equal(s2)
}

// isAbstractSigner checks whether the transaction signature is that of
// the abstract signer. The abstract signer is determined by V being equal
// to the chain identifier and r and s being 0.
func isAbstractSigner(tx *Transaction, chainId *big.Int) bool {
v, r, s := tx.RawSignatureValues()
return v.Cmp(chainId) == 0 && r.BitLen() == 0 && s.BitLen() == 0
}

func (s EIP86Signer) PublicKey(tx *Transaction) ([]byte, error) {
if isAbstractSigner(tx, s.chainId) {
return nil, errAbstractSigner
}
return s.EIP155Signer.PublicKey(tx)
}

// EIP155Transaction implements TransactionInterface using the
// EIP155 rules
type EIP155Signer struct {
Expand Down
Loading