Skip to content
Merged
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
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ jobs:
- name: golangci-lint
uses: golangci/golangci-lint-action@v3
with:
version: v1.56
version: v1.63
working-directory: .
args: --timeout 3m
skip-pkg-cache: true
Expand Down
16 changes: 11 additions & 5 deletions .golangci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,6 @@
run:
timeout: 10m
tests: true
# default is true. Enables skipping of directories:
# vendor$, third_party$, testdata$, examples$, Godeps$, builtin$
skip-dirs-use-default: true
# Include non-test files tagged as test-only.
# Context: https://github.com/ava-labs/avalanchego/pull/3173

linters:
disable-all: true
Expand All @@ -18,8 +13,19 @@ linters:
- ineffassign
- misspell
- unconvert
- typecheck
- unused
# - staticcheck
- bidichk
- durationcheck
- copyloopvar
- whitespace
# - revive # only certain checks enabled
- durationcheck
- gocheckcompilerdirectives
- reassign
- mirror
- tenv

linters-settings:
gofmt:
Expand Down
1 change: 0 additions & 1 deletion accounts/abi/abi_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1210,7 +1210,6 @@ func TestUnpackRevert(t *testing.T) {
{"4e487b7100000000000000000000000000000000000000000000000000000000000000ff", "unknown panic code: 0xff", nil},
}
for index, c := range cases {
index, c := index, c
t.Run(fmt.Sprintf("case %d", index), func(t *testing.T) {
t.Parallel()
got, err := UnpackRevert(common.Hex2Bytes(c.input))
Expand Down
2 changes: 1 addition & 1 deletion accounts/abi/bind/bind.go
Original file line number Diff line number Diff line change
Expand Up @@ -262,7 +262,7 @@ func Bind(types []string, abis []string, bytecodes []string, fsigs []map[string]
}
// Parse library references.
for pattern, name := range libs {
matched, err := regexp.Match("__\\$"+pattern+"\\$__", []byte(contracts[types[i]].InputBin))
matched, err := regexp.MatchString("__\\$"+pattern+"\\$__", contracts[types[i]].InputBin)
if err != nil {
log.Error("Could not search for pattern", "pattern", pattern, "contract", contracts[types[i]], "err", err)
}
Expand Down
1 change: 0 additions & 1 deletion accounts/abi/event_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -341,7 +341,6 @@ func TestEventTupleUnpack(t *testing.T) {

for _, tc := range testCases {
assert := assert.New(t)
tc := tc
t.Run(tc.name, func(t *testing.T) {
err := unpackTestEventData(tc.dest, tc.data, tc.jsonLog, assert)
if tc.error == "" {
Expand Down
1 change: 0 additions & 1 deletion accounts/abi/pack_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,6 @@ import (
func TestPack(t *testing.T) {
t.Parallel()
for i, test := range packUnpackTests {
i, test := i, test
t.Run(strconv.Itoa(i), func(t *testing.T) {
t.Parallel()
encb, err := hex.DecodeString(test.packed)
Expand Down
1 change: 0 additions & 1 deletion accounts/abi/reflect_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,6 @@ var reflectTests = []reflectTest{
func TestReflectNameToStruct(t *testing.T) {
t.Parallel()
for _, test := range reflectTests {
test := test
t.Run(test.name, func(t *testing.T) {
t.Parallel()
m, err := mapArgNamesToStructFields(test.args, reflect.ValueOf(test.struc))
Expand Down
3 changes: 0 additions & 3 deletions accounts/abi/topics_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,6 @@ func TestMakeTopics(t *testing.T) {
},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
got, err := MakeTopics(tt.args.query...)
Expand Down Expand Up @@ -383,7 +382,6 @@ func TestParseTopics(t *testing.T) {
tests := setupTopicsTests()

for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
createObj := tt.args.createObj()
Expand All @@ -403,7 +401,6 @@ func TestParseTopicsIntoMap(t *testing.T) {
tests := setupTopicsTests()

for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
outMap := make(map[string]interface{})
Expand Down
3 changes: 1 addition & 2 deletions accounts/abi/unpack_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -399,7 +399,6 @@ func TestMethodMultiReturn(t *testing.T) {
"Can not unpack into a slice with wrong types",
}}
for _, tc := range testCases {
tc := tc
t.Run(tc.name, func(t *testing.T) {
require := require.New(t)
err := abi.UnpackIntoInterface(tc.dest, "multi", data)
Expand Down Expand Up @@ -957,7 +956,7 @@ func TestOOMMaliciousInput(t *testing.T) {
}
encb, err := hex.DecodeString(test.enc)
if err != nil {
t.Fatalf("invalid hex: %s" + test.enc)
t.Fatalf("invalid hex: %s", test.enc)
}
_, err = abi.Methods["method"].Outputs.UnpackValues(encb)
if err == nil {
Expand Down
1 change: 0 additions & 1 deletion core/blockchain_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -291,7 +291,6 @@ func TestBlockChainOfflinePruningUngracefulShutdown(t *testing.T) {
return createBlockChain(db, pruningConfig, gspec, lastAcceptedHash)
}
for _, tt := range tests {
tt := tt
t.Run(tt.Name, func(t *testing.T) {
t.Parallel()
tt.testFunc(t, create)
Expand Down
1 change: 0 additions & 1 deletion core/predicate_check_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -293,7 +293,6 @@ func TestCheckPredicate(t *testing.T) {
expectedErr: ErrIntrinsicGas,
},
} {
test := test
t.Run(name, func(t *testing.T) {
require := require.New(t)
// Create the rules from TestChainConfig and update the predicates based on the test params
Expand Down
6 changes: 3 additions & 3 deletions core/rawdb/accessors_chain_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -291,10 +291,10 @@ func TestBlockReceiptStorage(t *testing.T) {
// Insert the receipt slice into the database and check presence
WriteReceipts(db, hash, 0, receipts)
if rs := ReadReceipts(db, hash, 0, 0, params.TestChainConfig); len(rs) == 0 {
t.Fatalf("no receipts returned")
t.Fatal("no receipts returned")
} else {
if err := checkReceiptsRLP(rs, receipts); err != nil {
t.Fatalf(err.Error())
t.Fatal(err)
}
}
// Delete the body and ensure that the receipts are no longer returned (metadata can't be recomputed)
Expand All @@ -308,7 +308,7 @@ func TestBlockReceiptStorage(t *testing.T) {
}
// Ensure that receipts without metadata can be returned without the block body too
if err := checkReceiptsRLP(ReadRawReceipts(db, hash, 0), receipts); err != nil {
t.Fatalf(err.Error())
t.Fatal(err)
}
// Sanity check that body and header alone without the receipt is a full purge
WriteHeader(db, header)
Expand Down
36 changes: 36 additions & 0 deletions core/types/header_ext.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// (c) 2025, Ava Labs, Inc. All rights reserved.
// See the file LICENSE for licensing terms.

package types

import (
"io"

ethtypes "github.com/ava-labs/libevm/core/types"
"github.com/ava-labs/libevm/rlp"
)

// HeaderExtra is a struct that contains extra fields used by Avalanche
// in the block header.
type HeaderExtra struct {
}

func (h *HeaderExtra) EncodeRLP(eth *ethtypes.Header, writer io.Writer) error {
panic("not implemented")
}

func (h *HeaderExtra) DecodeRLP(eth *ethtypes.Header, stream *rlp.Stream) error {
panic("not implemented")
}

func (h *HeaderExtra) EncodeJSON(eth *ethtypes.Header) ([]byte, error) {
panic("not implemented")
}

func (h *HeaderExtra) DecodeJSON(eth *ethtypes.Header, input []byte) error {
panic("not implemented")
}

func (h *HeaderExtra) PostCopy(dst *ethtypes.Header) {
panic("not implemented")
}
13 changes: 10 additions & 3 deletions core/types/state_account.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,15 @@ var (

type isMultiCoin bool

var IsMultiCoinPayloads = ethtypes.RegisterExtras[isMultiCoin]()
var (
extras = ethtypes.RegisterExtras[
ethtypes.NOOPHeaderHooks, *ethtypes.NOOPHeaderHooks,
ethtypes.NOOPBlockBodyHooks, *ethtypes.NOOPBlockBodyHooks,
isMultiCoin,
]()
IsMultiCoinPayloads = extras.StateAccount
)

func IsMultiCoin(a ethtypes.ExtraPayloadCarrier) bool {
return bool(IsMultiCoinPayloads.FromPayloadCarrier(a))
func IsMultiCoin(s ethtypes.StateOrSlimAccount) bool {
return bool(IsMultiCoinPayloads.Get(s))
}
1 change: 0 additions & 1 deletion eth/filters/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -350,7 +350,6 @@ func (api *FilterAPI) Logs(ctx context.Context, crit FilterCriteria) (*rpc.Subsc
select {
case logs := <-matchedLogs:
for _, log := range logs {
log := log
notifier.Notify(rpcSub.ID, &log)
}
case <-rpcSub.Err(): // client send an unsubscribe request
Expand Down
6 changes: 4 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
module github.com/ava-labs/coreth

go 1.22.8
go 1.23

toolchain go1.23.6

require (
github.com/VictoriaMetrics/fastcache v1.12.1
github.com/ava-labs/avalanchego v1.12.1-0.20250107220127-32f58b4fa9c8
github.com/ava-labs/libevm v1.13.14-0.1.0.rc-2
github.com/ava-labs/libevm v1.13.14-0.2.0.rc.3
github.com/crate-crypto/go-ipa v0.0.0-20231025140028-3c0104f4b233
github.com/davecgh/go-spew v1.1.1
github.com/deckarep/golang-set/v2 v2.1.0
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,8 @@ github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156/go.mod h1:Cb/ax
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
github.com/ava-labs/avalanchego v1.12.1-0.20250107220127-32f58b4fa9c8 h1:qN3MOBHB//Ynhgt5Vys3iVe42Sr0EWSeN18VL3ecXzE=
github.com/ava-labs/avalanchego v1.12.1-0.20250107220127-32f58b4fa9c8/go.mod h1:2B7+E5neLvkOr2zursGhebjU26d4AfB7RazPxBs8hHg=
github.com/ava-labs/libevm v1.13.14-0.1.0.rc-2 h1:CVbn0hSsPCl6gCkTCnqwuN4vtJgdVbkCqLXzYAE7qF8=
github.com/ava-labs/libevm v1.13.14-0.1.0.rc-2/go.mod h1:yBctIV/wnxXTF38h95943jvpuk4aj07TrjbpoGor6LQ=
github.com/ava-labs/libevm v1.13.14-0.2.0.rc.3 h1:1CWGo2icnX9dRqGQl7CFywYGIZWxe+ucy0w8NAsVTWE=
github.com/ava-labs/libevm v1.13.14-0.2.0.rc.3/go.mod h1:+Iol+sVQ1KyoBsHf3veyrBmHCXr3xXRWq6ZXkgVfNLU=
github.com/aymerick/raymond v2.0.3-0.20180322193309-b565731e1464+incompatible/go.mod h1:osfaiScAUVup+UC9Nfq76eWqDhXlp+4UYaA8uhTBO6g=
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
Expand Down
2 changes: 1 addition & 1 deletion metrics/json_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ func TestRegistryMarshallJSON(t *testing.T) {
r.Register("counter", NewCounter())
enc.Encode(r)
if s := b.String(); s != "{\"counter\":{\"count\":0}}\n" {
t.Fatalf(s)
t.Fatal(s)
}
}

Expand Down
34 changes: 22 additions & 12 deletions nativeasset/contract.go
Original file line number Diff line number Diff line change
Expand Up @@ -105,57 +105,67 @@ 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) {
if suppliedGas < c.GasCost {
env := accessibleState.GetPrecompileEnv()
if !env.UseGas(c.GasCost) {
return nil, 0, vmerrs.ErrOutOfGas
}
remainingGas = suppliedGas - c.GasCost
ret, err = c.run(env, accessibleState.GetStateDB(), caller, addr, input, readOnly)
// This precompile will be wrapped in a libevm `legacy` wrapper, which
// allows for the deprecated pattern of returning remaining gas by calling
// env.UseGas() on the difference between gas in and gas out. Since we call
// UseGas() ourselves, we therefore return `suppliedGas` unchanged to stop
// the legacy wrapper from double-counting spends.
return ret, suppliedGas, err
}

// run implements the contract logic, using `env.Gas()` and `env.UseGas()` in
// place of `suppliedGas` and returning `remainingGas`, respectively. This
// avoids mixing gas-accounting patterns when using env.Call().
func (c *NativeAssetCall) run(env vm.PrecompileEnvironment, stateDB contract.StateDB, caller common.Address, addr common.Address, input []byte, readOnly bool) (ret []byte, err error) {
if readOnly {
return nil, remainingGas, vmerrs.ErrExecutionReverted
return nil, vmerrs.ErrExecutionReverted
}

to, assetID, assetAmount, callData, err := UnpackNativeAssetCallInput(input)
if err != nil {
log.Debug("unpacking native asset call input failed", "err", err)
return nil, remainingGas, vmerrs.ErrExecutionReverted
return nil, vmerrs.ErrExecutionReverted
}

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, as documented on [big.Int.SetBytes].
if assetAmount.Sign() != 0 && stateDB.GetBalanceMultiCoin(caller, assetID).Cmp(assetAmount) < 0 {
return nil, remainingGas, vmerrs.ErrInsufficientBalance
return nil, vmerrs.ErrInsufficientBalance
}

snapshot := stateDB.Snapshot()

if !stateDB.Exist(to) {
if remainingGas < c.CallNewAccountGas {
return nil, 0, vmerrs.ErrOutOfGas
if !env.UseGas(c.CallNewAccountGas) {
return nil, 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())
ret, err = env.Call(to, callData, env.Gas(), 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
env.UseGas(env.Gas())
}
// TODO: consider clearing up unused snapshots:
//} else {
// evm.StateDB.DiscardSnapshot(snapshot)
}
return ret, remainingGas, err
return ret, err
}

type DeprecatedContract struct{}
Expand Down
6 changes: 3 additions & 3 deletions nativeasset/contract_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -239,8 +239,8 @@ func TestStatefulPrecompile(t *testing.T) {
precompileAddr: NativeAssetCallAddr,
input: PackNativeAssetCallInput(userAddr2, assetID, big.NewInt(50), nil),
value: big0,
gasInput: params.AssetCallApricot + params.CallNewAccountGas,
expectedGasRemaining: 0,
gasInput: params.AssetCallApricot + params.CallNewAccountGas + 123,
expectedGasRemaining: 123,
expectedErr: nil,
expectedResult: nil,
name: "native asset call: multicoin transfer",
Expand Down Expand Up @@ -459,7 +459,7 @@ func TestStatefulPrecompile(t *testing.T) {
evm := vm.NewEVM(vmCtx, vm.TxContext{}, stateDB, params.TestApricotPhase5Config, vm.Config{}) // Use ApricotPhase5Config because these precompiles are deprecated in ApricotPhase6.
ret, gasRemaining, err := evm.Call(vm.AccountRef(test.from), test.precompileAddr, test.input, test.gasInput, test.value)
// Place gas remaining check before error check, so that it is not skipped when there is an error
assert.Equal(t, test.expectedGasRemaining, gasRemaining, "unexpected gas remaining")
assert.Equalf(t, test.expectedGasRemaining, gasRemaining, "unexpected gas remaining (%d of %d)", gasRemaining, test.gasInput)

if test.expectedErr != nil {
assert.Equal(t, test.expectedErr, err, "expected error to match")
Expand Down
6 changes: 3 additions & 3 deletions params/config_extra.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,10 +59,10 @@ func SetEthUpgrades(c *ChainConfig) {
}

func GetExtra(c *ChainConfig) *extras.ChainConfig {
ex := payloads.FromChainConfig(c)
ex := payloads.ChainConfig.Get(c)
if ex == nil {
ex = &extras.ChainConfig{}
payloads.SetOnChainConfig(c, ex)
payloads.ChainConfig.Set(c, ex)
}
return ex
}
Expand All @@ -75,7 +75,7 @@ func Copy(c *ChainConfig) ChainConfig {

// WithExtra sets the extra payload on `c` and returns the modified argument.
func WithExtra(c *ChainConfig, extra *extras.ChainConfig) *ChainConfig {
payloads.SetOnChainConfig(c, extra)
payloads.ChainConfig.Set(c, extra)
return c
}

Expand Down
Loading
Loading