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

use libevm: params, core/vm, eth/tracers/* + some of core/types #662

Merged
merged 39 commits into from
Nov 6, 2024
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
314fe42
format: as subnet-evm
darioush Sep 25, 2024
72a4b00
take changes up to d72ff25 from subnet-evm
darioush Oct 2, 2024
b3647e3
complete use core/vm
darioush Sep 26, 2024
20754f7
format: as coreth
darioush Oct 2, 2024
6ff7f77
ci fixes
darioush Sep 26, 2024
512ae03
use race free version
darioush Sep 26, 2024
0baae1a
update version
darioush Sep 26, 2024
4fe802b
rebase new libevm
darioush Sep 27, 2024
df98c4e
remove WithExtras hack
darioush Oct 1, 2024
8e223b9
cleanup
darioush Oct 2, 2024
43dde81
fix genesis EthUpgrades
darioush Oct 3, 2024
0976d50
update libevm
darioush Oct 7, 2024
062dc35
Merge remote-tracking branch 'origin/master' into use-libevm
darioush Oct 11, 2024
80fb112
fix for merge
darioush Oct 11, 2024
357fba6
fix test
darioush Oct 11, 2024
6bf7ca2
move code to config/rules_extra.go
darioush Oct 11, 2024
fa77e8a
rename vars
darioush Oct 11, 2024
44468d6
refactor: reduce calling params.GetExtra
darioush Oct 11, 2024
023849c
more reduce params.GetExtra
darioush Oct 11, 2024
9a158f0
use upstream forks
darioush Oct 11, 2024
aa77826
pass bytes of predicate results to avoid parsing in params
darioush Oct 12, 2024
2abcd61
use more upstream types
darioush Oct 14, 2024
a54dac6
Merge branch 'master' of github.com:ava-labs/coreth into use-libevm
darioush Oct 14, 2024
546b697
nit
darioush Oct 14, 2024
ba3f538
nit
darioush Oct 14, 2024
bf9a87f
less use of params.Copy
darioush Oct 14, 2024
a1d7a11
reduce diff
darioush Oct 14, 2024
72a90dd
Review of `params` package in #662 (#674)
ARR4N Oct 18, 2024
4054dd4
review comments
darioush Oct 21, 2024
8f6d766
GetPredicateResultBytes: remove extra return
darioush Oct 21, 2024
51be0ca
review: reduce calls to params.GetExtra
darioush Oct 25, 2024
69f2ce9
review: rename nativeasset files
darioush Oct 25, 2024
2f3c9b2
refactor: move asset call logic to nativeasset
darioush Oct 25, 2024
aee7a95
review: IsShanghai+adding comments for OverrideNewEVMArgs
darioush Oct 25, 2024
7a5378f
review comments
darioush Oct 28, 2024
b996733
make chainConfigExtra()
darioush Oct 28, 2024
e6ec110
set difficulty to nil as well
darioush Oct 28, 2024
f575788
predicate results: alternate approach (similar to master) (#679)
darioush Nov 6, 2024
a203ea6
Use upstream account packages (#678)
darioush Nov 6, 2024
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
11 changes: 9 additions & 2 deletions core/evm.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,11 +50,18 @@ func init() {

type hooks struct{}

// OverrideNewEVMArgs is a hook that is called back when a new EVM is created.
// It allows for the modification of the EVM arguments before the EVM is created.
// Specifically, we set Random to be the same as Difficulty since Shanghai.
// This allows using the same jump table as upstream.
// Additionally we wrap the StateDB with the appropriate StateDB wrapper,
// which is used in coreth to process historical pre-AP1 blocks with the
// GetCommittedState method as it was historically.
func (hooks) OverrideNewEVMArgs(args *vm.NewEVMArgs) *vm.NewEVMArgs {
ceyonur marked this conversation as resolved.
Show resolved Hide resolved
rules := args.ChainConfig.Rules(args.BlockContext.BlockNumber, args.BlockContext.Random != nil, args.BlockContext.Time)
rules := args.ChainConfig.Rules(args.BlockContext.BlockNumber, params.IsMergeTODO, args.BlockContext.Time)
args.StateDB = wrapStateDB(rules, args.StateDB)

if params.GetRulesExtra(rules).IsDurango {
if rules.IsShanghai {
args.BlockContext.Random = new(common.Hash)
args.BlockContext.Random.SetBytes(args.BlockContext.Difficulty.Bytes())
darioush marked this conversation as resolved.
Show resolved Hide resolved
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"github.com/ava-labs/coreth/precompile/contract"
"github.com/ava-labs/coreth/vmerrs"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/vm"
"github.com/holiman/uint256"
)

Expand Down Expand Up @@ -73,7 +74,8 @@ func (b *NativeAssetBalance) Run(accessibleState contract.AccessibleState, calle
// NativeAssetCall atomically transfers a native asset to a recipient address as well as calling that
// address
type NativeAssetCall struct {
GasCost uint64
GasCost uint64
CallNewAccountGas uint64
}

// PackNativeAssetCallInput packs the arguments into the required input data for a transaction to be passed into
Expand Down Expand Up @@ -102,8 +104,56 @@ func UnpackNativeAssetCallInput(input []byte) (common.Address, common.Hash, *big

// Run implements StatefulPrecompiledContract
func (c *NativeAssetCall) Run(accessibleState contract.AccessibleState, caller common.Address, addr common.Address, input []byte, suppliedGas uint64, readOnly bool) (ret []byte, remainingGas uint64, err error) {
// input: encodePacked(address 20 bytes, assetID 32 bytes, assetAmount 32 bytes, callData variable length bytes)
return accessibleState.NativeAssetCall(caller, input, suppliedGas, c.GasCost, readOnly)
if suppliedGas < c.GasCost {
return nil, 0, vmerrs.ErrOutOfGas
}
remainingGas = suppliedGas - c.GasCost
darioush marked this conversation as resolved.
Show resolved Hide resolved

if readOnly {
return nil, remainingGas, vmerrs.ErrExecutionReverted
darioush marked this conversation as resolved.
Show resolved Hide resolved
}

to, assetID, assetAmount, callData, err := UnpackNativeAssetCallInput(input)
if err != nil {
return nil, remainingGas, vmerrs.ErrExecutionReverted
darioush marked this conversation as resolved.
Show resolved Hide resolved
}

stateDB := accessibleState.GetStateDB()
// Note: it is not possible for a negative assetAmount to be passed in here due to the fact that decoding a
// byte slice into a *big.Int type will always return a positive value.
darioush marked this conversation as resolved.
Show resolved Hide resolved
if assetAmount.Sign() != 0 && stateDB.GetBalanceMultiCoin(caller, assetID).Cmp(assetAmount) < 0 {
return nil, remainingGas, vmerrs.ErrInsufficientBalance
}

snapshot := stateDB.Snapshot()

if !stateDB.Exist(to) {
if remainingGas < c.CallNewAccountGas {
return nil, 0, vmerrs.ErrOutOfGas
}
remainingGas -= c.CallNewAccountGas
stateDB.CreateAccount(to)
}

// Send [assetAmount] of [assetID] to [to] address
stateDB.SubBalanceMultiCoin(caller, assetID, assetAmount)
stateDB.AddBalanceMultiCoin(to, assetID, assetAmount)

ret, remainingGas, err = accessibleState.Call(to, callData, remainingGas, new(uint256.Int), vm.WithUNSAFECallerAddressProxying())

// When an error was returned by the EVM or when setting the creation code
// above we revert to the snapshot and consume any gas remaining. Additionally
// when we're in homestead this also counts for code storage gas errors.
if err != nil {
stateDB.RevertToSnapshot(snapshot)
if err != vmerrs.ErrExecutionReverted {
remainingGas = 0
}
// TODO: consider clearing up unused snapshots:
//} else {
// evm.StateDB.DiscardSnapshot(snapshot)
}
return ret, remainingGas, err
}

type DeprecatedContract struct{}
Expand Down
File renamed without changes.
57 changes: 4 additions & 53 deletions params/hooks_libevm.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ func (r RulesExtra) CanExecuteTransaction(_ common.Address, _ *common.Address, _
var PrecompiledContractsApricotPhase2 = map[common.Address]contract.StatefulPrecompiledContract{
nativeasset.GenesisContractAddr: &nativeasset.DeprecatedContract{},
nativeasset.NativeAssetBalanceAddr: &nativeasset.NativeAssetBalance{GasCost: AssetBalanceApricot},
nativeasset.NativeAssetCallAddr: &nativeasset.NativeAssetCall{GasCost: AssetCallApricot},
nativeasset.NativeAssetCallAddr: &nativeasset.NativeAssetCall{GasCost: AssetCallApricot, CallNewAccountGas: CallNewAccountGas},
}

var PrecompiledContractsApricotPhasePre6 = map[common.Address]contract.StatefulPrecompiledContract{
Expand All @@ -48,7 +48,7 @@ var PrecompiledContractsApricotPhasePre6 = map[common.Address]contract.StatefulP
var PrecompiledContractsApricotPhase6 = map[common.Address]contract.StatefulPrecompiledContract{
nativeasset.GenesisContractAddr: &nativeasset.DeprecatedContract{},
nativeasset.NativeAssetBalanceAddr: &nativeasset.NativeAssetBalance{GasCost: AssetBalanceApricot},
nativeasset.NativeAssetCallAddr: &nativeasset.NativeAssetCall{GasCost: AssetCallApricot},
nativeasset.NativeAssetCallAddr: &nativeasset.NativeAssetCall{GasCost: AssetCallApricot, CallNewAccountGas: CallNewAccountGas},
}

var PrecompiledContractsBanff = map[common.Address]contract.StatefulPrecompiledContract{
Expand Down Expand Up @@ -166,57 +166,8 @@ func (a accessableState) GetSnowContext() *snow.Context {
return GetExtra(a.env.ChainConfig()).SnowCtx
}

func (a accessableState) NativeAssetCall(caller common.Address, input []byte, suppliedGas uint64, gasCost uint64, readOnly bool) (ret []byte, remainingGas uint64, err error) {
darioush marked this conversation as resolved.
Show resolved Hide resolved
if suppliedGas < gasCost {
return nil, 0, vmerrs.ErrOutOfGas
}
remainingGas = suppliedGas - gasCost

if readOnly {
return nil, remainingGas, vmerrs.ErrExecutionReverted
}

to, assetID, assetAmount, callData, err := nativeasset.UnpackNativeAssetCallInput(input)
if err != nil {
return nil, remainingGas, vmerrs.ErrExecutionReverted
}

stateDB := a.GetStateDB()
// Note: it is not possible for a negative assetAmount to be passed in here due to the fact that decoding a
// byte slice into a *big.Int type will always return a positive value.
if assetAmount.Sign() != 0 && stateDB.GetBalanceMultiCoin(caller, assetID).Cmp(assetAmount) < 0 {
return nil, remainingGas, vmerrs.ErrInsufficientBalance
}

snapshot := stateDB.Snapshot()

if !stateDB.Exist(to) {
if remainingGas < CallNewAccountGas {
return nil, 0, vmerrs.ErrOutOfGas
}
remainingGas -= CallNewAccountGas
stateDB.CreateAccount(to)
}

// Send [assetAmount] of [assetID] to [to] address
stateDB.SubBalanceMultiCoin(caller, assetID, assetAmount)
stateDB.AddBalanceMultiCoin(to, assetID, assetAmount)

ret, remainingGas, err = a.env.Call(to, callData, remainingGas, new(uint256.Int), vm.WithUNSAFECallerAddressProxying())

// When an error was returned by the EVM or when setting the creation code
// above we revert to the snapshot and consume any gas remaining. Additionally
// when we're in homestead this also counts for code storage gas errors.
if err != nil {
stateDB.RevertToSnapshot(snapshot)
if err != vmerrs.ErrExecutionReverted {
remainingGas = 0
}
// TODO: consider clearing up unused snapshots:
//} else {
// evm.StateDB.DiscardSnapshot(snapshot)
}
return ret, remainingGas, err
func (a accessableState) Call(addr common.Address, input []byte, gas uint64, value *uint256.Int, _ ...vm.CallOption) (ret []byte, gasRemaining uint64, _ error) {
return a.env.Call(addr, input, gas, value)
}

type BlockContext struct {
Expand Down
2 changes: 1 addition & 1 deletion plugin/evm/block.go
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ type Block struct {

// newBlock returns a new Block wrapping the ethBlock type and implementing the snowman.Block interface
func (vm *VM) newBlock(ethBlock *types.Block) (*Block, error) {
isApricotPhase5 := params.GetExtra(vm.chainConfig).IsApricotPhase5(ethBlock.Time())
isApricotPhase5 := vm.chainConfigExtra.IsApricotPhase5(ethBlock.Time())
atomicTxs, err := ExtractAtomicTxs(ethBlock.ExtData(), isApricotPhase5, vm.codec)
if err != nil {
return nil, err
Expand Down
20 changes: 9 additions & 11 deletions plugin/evm/export_tx.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,9 +69,8 @@ func (utx *UnsignedExportTx) InputUTXOs() set.Set[ids.ID] {
// Verify this transaction is well-formed
func (utx *UnsignedExportTx) Verify(
ctx *snow.Context,
rules params.Rules,
rules params.RulesExtra,
) error {
rulesExtra := params.GetRulesExtra(rules)
switch {
case utx == nil:
return errNilTx
Expand All @@ -84,7 +83,7 @@ func (utx *UnsignedExportTx) Verify(
}

// Make sure that the tx has a valid peer chain ID
if rulesExtra.IsApricotPhase5 {
if rules.IsApricotPhase5 {
// Note that SameSubnet verifies that [tx.DestinationChain] isn't this
// chain's ID
if err := verify.SameSubnet(context.TODO(), ctx, utx.DestinationChain); err != nil {
Expand All @@ -100,7 +99,7 @@ func (utx *UnsignedExportTx) Verify(
if err := in.Verify(); err != nil {
return err
}
if rulesExtra.IsBanff && in.AssetID != ctx.AVAXAssetID {
if rules.IsBanff && in.AssetID != ctx.AVAXAssetID {
return errExportNonAVAXInputBanff
}
}
Expand All @@ -113,14 +112,14 @@ func (utx *UnsignedExportTx) Verify(
if assetID != ctx.AVAXAssetID && utx.DestinationChain == constants.PlatformChainID {
return errWrongChainID
}
if rulesExtra.IsBanff && assetID != ctx.AVAXAssetID {
if rules.IsBanff && assetID != ctx.AVAXAssetID {
return errExportNonAVAXOutputBanff
}
}
if !avax.IsSortedTransferableOutputs(utx.ExportedOutputs, Codec) {
return errOutputsNotSorted
}
if rulesExtra.IsApricotPhase1 && !utils.IsSortedAndUnique(utx.Ins) {
if rules.IsApricotPhase1 && !utils.IsSortedAndUnique(utx.Ins) {
return errInputsNotSortedUnique
}

Expand Down Expand Up @@ -181,9 +180,8 @@ func (utx *UnsignedExportTx) SemanticVerify(
stx *Tx,
_ *Block,
baseFee *big.Int,
rules params.Rules,
rules params.RulesExtra,
) error {
rulesExtra := params.GetRulesExtra(rules)
if err := utx.Verify(vm.ctx, rules); err != nil {
return err
}
Expand All @@ -192,8 +190,8 @@ func (utx *UnsignedExportTx) SemanticVerify(
fc := avax.NewFlowChecker()
switch {
// Apply dynamic fees to export transactions as of Apricot Phase 3
case rulesExtra.IsApricotPhase3:
gasUsed, err := stx.GasUsed(rulesExtra.IsApricotPhase5)
case rules.IsApricotPhase3:
gasUsed, err := stx.GasUsed(rules.IsApricotPhase5)
if err != nil {
return err
}
Expand Down Expand Up @@ -317,7 +315,7 @@ func (vm *VM) newExportTx(
avaxNeeded = amount
}

rules := params.GetRulesExtra(vm.currentRules())
rules := vm.currentRules()
switch {
case rules.IsApricotPhase3:
utx := &UnsignedExportTx{
Expand Down
6 changes: 3 additions & 3 deletions plugin/evm/export_tx_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -526,7 +526,7 @@ func TestExportTxSemanticVerify(t *testing.T) {
tx *Tx
signers [][]*secp256k1.PrivateKey
baseFee *big.Int
rules params.Rules
rules params.RulesExtra
shouldErr bool
}{
{
Expand Down Expand Up @@ -1633,7 +1633,7 @@ func TestNewExportTx(t *testing.T) {
tests := []struct {
name string
genesis string
rules params.Rules
rules params.RulesExtra
bal uint64
expectedBurnedAVAX uint64
}{
Expand Down Expand Up @@ -1806,7 +1806,7 @@ func TestNewExportTxMulticoin(t *testing.T) {
tests := []struct {
name string
genesis string
rules params.Rules
rules params.RulesExtra
bal uint64
balmc uint64
}{
Expand Down
26 changes: 12 additions & 14 deletions plugin/evm/import_tx.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,9 +62,8 @@ func (utx *UnsignedImportTx) InputUTXOs() set.Set[ids.ID] {
// Verify this transaction is well-formed
func (utx *UnsignedImportTx) Verify(
ctx *snow.Context,
rules params.Rules,
rules params.RulesExtra,
) error {
rulesExtra := params.GetRulesExtra(rules)
switch {
case utx == nil:
return errNilTx
Expand All @@ -74,12 +73,12 @@ func (utx *UnsignedImportTx) Verify(
return errWrongNetworkID
case ctx.ChainID != utx.BlockchainID:
return errWrongBlockchainID
case rulesExtra.IsApricotPhase3 && len(utx.Outs) == 0:
case rules.IsApricotPhase3 && len(utx.Outs) == 0:
return errNoEVMOutputs
}

// Make sure that the tx has a valid peer chain ID
if rulesExtra.IsApricotPhase5 {
if rules.IsApricotPhase5 {
// Note that SameSubnet verifies that [tx.SourceChain] isn't this
// chain's ID
if err := verify.SameSubnet(context.TODO(), ctx, utx.SourceChain); err != nil {
Expand All @@ -95,7 +94,7 @@ func (utx *UnsignedImportTx) Verify(
if err := out.Verify(); err != nil {
return fmt.Errorf("EVM Output failed verification: %w", err)
}
if rulesExtra.IsBanff && out.AssetID != ctx.AVAXAssetID {
if rules.IsBanff && out.AssetID != ctx.AVAXAssetID {
return errImportNonAVAXOutputBanff
}
}
Expand All @@ -104,19 +103,19 @@ func (utx *UnsignedImportTx) Verify(
if err := in.Verify(); err != nil {
return fmt.Errorf("atomic input failed verification: %w", err)
}
if rulesExtra.IsBanff && in.AssetID() != ctx.AVAXAssetID {
if rules.IsBanff && in.AssetID() != ctx.AVAXAssetID {
return errImportNonAVAXInputBanff
}
}
if !utils.IsSortedAndUnique(utx.ImportedInputs) {
return errInputsNotSortedUnique
}

if rulesExtra.IsApricotPhase2 {
if rules.IsApricotPhase2 {
if !utils.IsSortedAndUnique(utx.Outs) {
return errOutputsNotSortedUnique
}
} else if rulesExtra.IsApricotPhase1 {
} else if rules.IsApricotPhase1 {
if !slices.IsSortedFunc(utx.Outs, EVMOutput.Compare) {
return errOutputsNotSorted
}
Expand Down Expand Up @@ -182,9 +181,8 @@ func (utx *UnsignedImportTx) SemanticVerify(
stx *Tx,
parent *Block,
baseFee *big.Int,
rules params.Rules,
rules params.RulesExtra,
) error {
rulesExtra := params.GetRulesExtra(rules)
if err := utx.Verify(vm.ctx, rules); err != nil {
return err
}
Expand All @@ -193,8 +191,8 @@ func (utx *UnsignedImportTx) SemanticVerify(
fc := avax.NewFlowChecker()
switch {
// Apply dynamic fees to import transactions as of Apricot Phase 3
case rulesExtra.IsApricotPhase3:
gasUsed, err := stx.GasUsed(rulesExtra.IsApricotPhase5)
case rules.IsApricotPhase3:
gasUsed, err := stx.GasUsed(rules.IsApricotPhase5)
if err != nil {
return err
}
Expand All @@ -205,7 +203,7 @@ func (utx *UnsignedImportTx) SemanticVerify(
fc.Produce(vm.ctx.AVAXAssetID, txFee)

// Apply fees to import transactions as of Apricot Phase 2
case rulesExtra.IsApricotPhase2:
case rules.IsApricotPhase2:
fc.Produce(vm.ctx.AVAXAssetID, params.AvalancheAtomicTxFee)
}
for _, out := range utx.Outs {
Expand Down Expand Up @@ -350,7 +348,7 @@ func (vm *VM) newImportTxWithUTXOs(
})
}

rules := params.GetRulesExtra(vm.currentRules())
rules := vm.currentRules()

var (
txFeeWithoutChange uint64
Expand Down
2 changes: 1 addition & 1 deletion plugin/evm/import_tx_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -443,7 +443,7 @@ func TestNewImportTx(t *testing.T) {
if err != nil {
t.Fatal(err)
}
rules := params.GetRulesExtra(vm.currentRules())
rules := vm.currentRules()
switch {
case rules.IsApricotPhase3:
actualCost, err := importTx.GasUsed(rules.IsApricotPhase5)
Expand Down
Loading
Loading