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

Update precompile setup for warp #390

Merged
merged 19 commits into from
Nov 28, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
c30bee7
Migrate warp backend from Subnet-EVM
aaronbuchwald Nov 13, 2023
1a36626
warp/handlers: update duration greater than assertion to pass on windows
aaronbuchwald Nov 13, 2023
c38a9ef
Update precompile setup for warp
aaronbuchwald Nov 13, 2023
2ddaa54
Pass predicate context through block build / verify
aaronbuchwald Nov 14, 2023
9a6aa1d
Fix up dynamic fee extra data window handling post D-Upgrade
aaronbuchwald Nov 14, 2023
17909e8
Remove duration stats test from warp network handler
aaronbuchwald Nov 14, 2023
ad5959e
Merge branch 'warp-backend' into warp-precompile-setup
aaronbuchwald Nov 14, 2023
73bd5f4
Fix trailing newline
aaronbuchwald Nov 14, 2023
2daa47b
Merge branch 'master' into warp-backend
aaronbuchwald Nov 17, 2023
1f73db7
Update signature aggregator constructor comment
aaronbuchwald Nov 17, 2023
71ccb87
Add back CanTransferMC and TransferMultiCoin
aaronbuchwald Nov 17, 2023
e6f8ca2
Remove duplicate from reserved address space
aaronbuchwald Nov 17, 2023
65d3368
remove duplicate check in different package
aaronbuchwald Nov 17, 2023
9711885
Update warp/aggregator/aggregator.go
aaronbuchwald Nov 27, 2023
7c0a0c2
Merge branch 'master' into warp-backend
aaronbuchwald Nov 28, 2023
3853d48
core/vm: move native asset contracts to separate file
aaronbuchwald Nov 28, 2023
676bcac
Remove unused istanbul field from txpool
aaronbuchwald Nov 28, 2023
d1bb80b
Merge branch 'warp-backend' into warp-precompile-setup
aaronbuchwald Nov 28, 2023
5551ecc
Merge branch 'master' into warp-precompile-setup
aaronbuchwald Nov 28, 2023
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
19 changes: 12 additions & 7 deletions consensus/dummy/consensus.go
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ func (self *DummyEngine) verifyHeaderGasFields(config *params.ChainConfig, heade
if err != nil {
return fmt.Errorf("failed to calculate base fee: %w", err)
}
if !bytes.Equal(expectedRollupWindowBytes, header.Extra) {
if len(header.Extra) < len(expectedRollupWindowBytes) || !bytes.Equal(expectedRollupWindowBytes, header.Extra[:len(expectedRollupWindowBytes)]) {
return fmt.Errorf("expected rollup window bytes: %x, found %x", expectedRollupWindowBytes, header.Extra)
}
if header.BaseFee == nil {
Expand Down Expand Up @@ -194,16 +194,21 @@ func (self *DummyEngine) verifyHeader(chain consensus.ChainHeaderReader, header
if uncle {
return errUnclesUnsupported
}
// Ensure that the header's extra-data section is of a reasonable size
if !config.IsApricotPhase3(header.Time) {
switch {
case config.IsDUpgrade(header.Time):
if len(header.Extra) < params.DynamicFeeExtraDataSize {
return fmt.Errorf("expected extra-data field length >= %d, found %d", params.DynamicFeeExtraDataSize, len(header.Extra))
}
case config.IsApricotPhase3(header.Time):
if len(header.Extra) != params.DynamicFeeExtraDataSize {
return fmt.Errorf("expected extra-data field to be: %d, but found %d", params.DynamicFeeExtraDataSize, len(header.Extra))
}
default:
if uint64(len(header.Extra)) > params.MaximumExtraDataSize {
return fmt.Errorf("extra-data too long: %d > %d", len(header.Extra), params.MaximumExtraDataSize)
}
} else {
if uint64(len(header.Extra)) != params.ApricotPhase3ExtraDataSize {
return fmt.Errorf("expected extra-data field to be: %d, but found %d", params.ApricotPhase3ExtraDataSize, len(header.Extra))
}
}

// Ensure gas-related header fields are correct
if err := self.verifyHeaderGasFields(config, header, parent); err != nil {
return err
Expand Down
10 changes: 6 additions & 4 deletions consensus/dummy/dynamic_fees.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,13 +46,15 @@ func CalcBaseFee(config *params.ChainConfig, parent *types.Header, timestamp uin
isApricotPhase5 = config.IsApricotPhase5(parent.Time)
)
if !isApricotPhase3 || parent.Number.Cmp(common.Big0) == 0 {
initialSlice := make([]byte, params.ApricotPhase3ExtraDataSize)
initialSlice := make([]byte, params.DynamicFeeExtraDataSize)
initialBaseFee := big.NewInt(params.ApricotPhase3InitialBaseFee)
return initialSlice, initialBaseFee, nil
}
if uint64(len(parent.Extra)) != params.ApricotPhase3ExtraDataSize {
return nil, nil, fmt.Errorf("expected length of parent extra data to be %d, but found %d", params.ApricotPhase3ExtraDataSize, len(parent.Extra))

if uint64(len(parent.Extra)) < params.DynamicFeeExtraDataSize {
return nil, nil, fmt.Errorf("expected length of parent extra data to be %d, but found %d", params.DynamicFeeExtraDataSize, len(parent.Extra))
}
dynamicFeeWindow := parent.Extra[:params.DynamicFeeExtraDataSize]

if timestamp < parent.Time {
return nil, nil, fmt.Errorf("cannot calculate base fee for timestamp (%d) prior to parent timestamp (%d)", timestamp, parent.Time)
Expand All @@ -61,7 +63,7 @@ func CalcBaseFee(config *params.ChainConfig, parent *types.Header, timestamp uin

// roll the window over by the difference between the timestamps to generate
// the new rollup window.
newRollupWindow, err := rollLongWindow(parent.Extra, int(roll))
newRollupWindow, err := rollLongWindow(dynamicFeeWindow, int(roll))
if err != nil {
return nil, nil, err
}
Expand Down
2 changes: 1 addition & 1 deletion core/bench_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ func genValueTx(nbytes int) func(int, *BlockGen) {
return func(i int, gen *BlockGen) {
toaddr := common.Address{}
data := make([]byte, nbytes)
gas, _ := IntrinsicGas(data, nil, false, false, false, false)
gas, _ := IntrinsicGas(data, nil, false, params.Rules{})
signer := types.MakeSigner(gen.config, big.NewInt(int64(i)), gen.header.Time)
tx, _ := types.SignTx(types.NewTransaction(gen.TxNonce(benchRootAddr), toaddr, big.NewInt(1), gas, big.NewInt(225000000000), data), signer, benchRootKey)
gen.AddTx(tx)
Expand Down
13 changes: 12 additions & 1 deletion core/chain_makers.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,11 @@ func (b *BlockGen) SetExtra(data []byte) {
b.header.Extra = data
}

// AppendExtra appends data to the extra data field of the generated block.
func (b *BlockGen) AppendExtra(data []byte) {
b.header.Extra = append(b.header.Extra, data...)
}

// SetNonce sets the nonce field of the generated block.
func (b *BlockGen) SetNonce(nonce types.BlockNonce) {
b.header.Nonce = nonce
Expand All @@ -103,7 +108,8 @@ func (b *BlockGen) addTx(bc *BlockChain, vmConfig vm.Config, tx *types.Transacti
b.SetCoinbase(common.Address{})
}
b.statedb.SetTxContext(tx.Hash(), len(b.txs))
receipt, err := ApplyTransaction(b.config, bc, &b.header.Coinbase, b.gasPool, b.statedb, b.header, tx, &b.header.GasUsed, vmConfig)
blockContext := NewEVMBlockContext(b.header, bc, &b.header.Coinbase)
receipt, err := ApplyTransaction(b.config, bc, blockContext, b.gasPool, b.statedb, b.header, tx, &b.header.GasUsed, vmConfig)
if err != nil {
panic(err)
}
Expand Down Expand Up @@ -246,6 +252,11 @@ func GenerateChain(config *params.ChainConfig, parent *types.Block, engine conse
b := &BlockGen{i: i, chain: blocks, parent: parent, statedb: statedb, config: config, engine: engine}
b.header = makeHeader(chainreader, config, parent, gap, statedb, b.engine)

err := ApplyUpgrades(config, &parent.Header().Time, b, statedb)
if err != nil {
return nil, nil, fmt.Errorf("failed to configure precompiles %v", err)
}

// Execute any user modifications to the block
if gen != nil {
gen(i, b)
Expand Down
30 changes: 30 additions & 0 deletions core/evm.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,9 @@ import (
"github.com/ava-labs/coreth/consensus"
"github.com/ava-labs/coreth/core/types"
"github.com/ava-labs/coreth/core/vm"
"github.com/ava-labs/coreth/predicate"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/log"
//"github.com/ethereum/go-ethereum/log"
)

Expand All @@ -48,6 +50,33 @@ type ChainContext interface {

// NewEVMBlockContext creates a new context for use in the EVM.
func NewEVMBlockContext(header *types.Header, chain ChainContext, author *common.Address) vm.BlockContext {
predicateBytes, ok := predicate.GetPredicateResultBytes(header.Extra)
if !ok {
return newEVMBlockContext(header, chain, author, nil)
}
// Prior to the DUpgrade, the VM enforces the extra data is smaller than or
// equal to this size. After the DUpgrade, the VM pre-verifies the extra
// data past the dynamic fee rollup window is valid.
predicateResults, err := predicate.ParseResults(predicateBytes)
if err != nil {
log.Error("failed to parse predicate results creating new block context", "err", err, "extra", header.Extra)
// As mentioned above, we pre-verify the extra data to ensure this never happens.
// If we hit an error, construct a new block context rather than use a potentially half initialized value
// as defense in depth.
return newEVMBlockContext(header, chain, author, nil)
}
return newEVMBlockContext(header, chain, author, predicateResults)
}

// NewEVMBlockContextWithPredicateResults creates a new context for use in the EVM with an override for the predicate results that is not present
// in header.Extra.
// This function is used to create a BlockContext when the header Extra data is not fully formed yet and it's more efficient to pass in predicateResults
// directly rather than re-encode the latest results when executing each individaul transaction.
func NewEVMBlockContextWithPredicateResults(header *types.Header, chain ChainContext, author *common.Address, predicateResults *predicate.Results) vm.BlockContext {
return newEVMBlockContext(header, chain, author, predicateResults)
}

func newEVMBlockContext(header *types.Header, chain ChainContext, author *common.Address, predicateResults *predicate.Results) vm.BlockContext {
var (
beneficiary common.Address
baseFee *big.Int
Expand All @@ -68,6 +97,7 @@ func NewEVMBlockContext(header *types.Header, chain ChainContext, author *common
Transfer: Transfer,
TransferMultiCoin: TransferMultiCoin,
GetHash: GetHashFn(header, chain),
PredicateResults: predicateResults,
Coinbase: beneficiary,
BlockNumber: new(big.Int).Set(header.Number),
Time: header.Time,
Expand Down
5 changes: 4 additions & 1 deletion core/genesis.go
Original file line number Diff line number Diff line change
Expand Up @@ -266,7 +266,10 @@ func (g *Genesis) toBlock(db ethdb.Database, triedb *trie.Database) *types.Block
}

// Configure any stateful precompiles that should be enabled in the genesis.
g.Config.CheckConfigurePrecompiles(nil, types.NewBlockWithHeader(head), statedb)
err = ApplyPrecompileActivations(g.Config, nil, types.NewBlockWithHeader(head), statedb)
if err != nil {
panic(fmt.Sprintf("unable to configure precompiles in genesis block: %v", err))
}

for addr, account := range g.Alloc {
statedb.AddBalance(addr, account.Balance)
Expand Down
61 changes: 61 additions & 0 deletions core/predicate_check.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
// (c) 2023, Ava Labs, Inc. All rights reserved.
// See the file LICENSE for licensing terms.

package core

import (
"errors"
"fmt"

"github.com/ava-labs/coreth/core/types"
"github.com/ava-labs/coreth/params"
"github.com/ava-labs/coreth/precompile/precompileconfig"
"github.com/ava-labs/coreth/predicate"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/log"
)

var ErrMissingPredicateContext = errors.New("missing predicate context")

// CheckPredicates verifies the predicates of [tx] and returns the result. Returning an error invalidates the block.
func CheckPredicates(rules params.Rules, predicateContext *precompileconfig.PredicateContext, tx *types.Transaction) (map[common.Address][]byte, error) {
// Check that the transaction can cover its IntrinsicGas (including the gas required by the predicate) before
// verifying the predicate.
intrinsicGas, err := IntrinsicGas(tx.Data(), tx.AccessList(), tx.To() == nil, rules)
if err != nil {
return nil, err
}
if tx.Gas() < intrinsicGas {
return nil, fmt.Errorf("%w for predicate verification (%d) < intrinsic gas (%d)", ErrIntrinsicGas, tx.Gas(), intrinsicGas)
}

predicateResults := make(map[common.Address][]byte)
// Short circuit early if there are no precompile predicates to verify
if len(rules.Predicaters) == 0 {
return predicateResults, nil
}

// Prepare the predicate storage slots from the transaction's access list
predicateArguments := predicate.PreparePredicateStorageSlots(rules, tx.AccessList())

// If there are no predicates to verify, return early and skip requiring the proposervm block
// context to be populated.
if len(predicateArguments) == 0 {
return predicateResults, nil
}

if predicateContext == nil || predicateContext.ProposerVMBlockCtx == nil {
return nil, ErrMissingPredicateContext
}

for address, predicates := range predicateArguments {
// Since [address] is only added to [predicateArguments] when there's a valid predicate in the ruleset
// there's no need to check if the predicate exists here.
predicaterContract := rules.Predicaters[address]
res := predicaterContract.VerifyPredicate(predicateContext, predicates)
log.Debug("predicate verify", "tx", tx.Hash(), "address", address, "res", res)
predicateResults[address] = res
}

return predicateResults, nil
}
Loading