Skip to content

Commit 93df6d8

Browse files
committed
Merge branch 'main' into arr4n/rename-go-mod-auto
2 parents a082971 + 88c00c6 commit 93df6d8

File tree

6 files changed

+250
-13
lines changed

6 files changed

+250
-13
lines changed

.github/workflows/go.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,9 @@ name: Go
33
on:
44
# DO NOT MERGE: disabled while developing auto-renaming
55
# push:
6-
# branches: [ libevm ]
6+
# branches: [ main ]
77
# pull_request:
8-
# branches: [ libevm ]
8+
# branches: [ main ]
99
workflow_dispatch:
1010

1111
jobs:
@@ -19,6 +19,6 @@ jobs:
1919
go-version: 1.21.4
2020
- name: Run tests
2121
run: | # Upstream flakes are race conditions exacerbated by concurrent tests
22-
FLAKY_REGEX='go-ethereum/(eth|eth/tracers/js|eth/tracers/logger|accounts/keystore|eth/downloader|miner|ethclient|ethclient/gethclient|eth/catalyst)$';
22+
FLAKY_REGEX='go-ethereum/(eth|eth/tracers/js|eth/tracers/logger|accounts/abi/bind|accounts/keystore|eth/downloader|miner|ethclient|ethclient/gethclient|eth/catalyst)$';
2323
go list ./... | grep -P "${FLAKY_REGEX}" | xargs -n 1 go test -short;
2424
go test -short $(go list ./... | grep -Pv "${FLAKY_REGEX}");

.github/workflows/golangci-lint.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,9 @@ name: golangci-lint
33
on:
44
# DO NOT MERGE: disabled while developing auto-renaming
55
# push:
6-
# branches: [ libevm ]
6+
# branches: [ main ]
77
# pull_request:
8-
# branches: [ libevm ]
8+
# branches: [ main ]
99
workflow_dispatch:
1010

1111
permissions:

.github/workflows/libevm-delta.yml

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@ name: libevm delta
22

33
on:
44
push:
5-
branches: [ libevm ]
5+
branches: [ main ]
66
pull_request:
7-
branches: [ libevm ]
7+
branches: [ main ]
88
workflow_dispatch:
99

1010
jobs:
@@ -26,13 +26,14 @@ jobs:
2626
git diff --diff-filter=a --word-diff --unified=0 --color=always \
2727
libevm-base \
2828
':(exclude).golangci.yml' \
29-
':(exclude).github/**';
29+
':(exclude).github/**' \
30+
':(exclude)README.md';
3031
31-
- name: git diff libevm-base..libevm
32+
- name: git diff libevm-base..main
3233
run: |
33-
git checkout libevm --;
34+
git checkout main --;
3435
git diff --diff-filter=a --word-diff --unified=0 --color=always \
3536
libevm-base \
3637
':(exclude).golangci.yml' \
37-
':(exclude).github/**';
38-
38+
':(exclude).github/**' \
39+
':(exclude)README.md';

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -361,4 +361,4 @@ The libevm (i) _additions_ to the go-ethereum library (i.e. all code in files wi
361361
be it a directory or file name); and (ii) _modifications_ to existing go-ethereum code; are licensed under the
362362
[GNU Lesser General Public License v3.0](https://www.gnu.org/licenses/lgpl-3.0.en.html),
363363
also included in our repository in the `COPYING.LESSER` file. A comprehensive outline of _modifications_ is
364-
produced by the [libevm delta workflow](https://github.com/ava-labs/go-ethereum/actions/workflows/libevm-delta.yml).
364+
produced by the [libevm delta workflow](https://github.com/ava-labs/libevm/actions/workflows/libevm-delta.yml).

core/state/state.libevm.go

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
// Copyright 2024 the libevm authors.
2+
//
3+
// The libevm additions to go-ethereum are free software: you can redistribute
4+
// them and/or modify them under the terms of the GNU Lesser General Public License
5+
// as published by the Free Software Foundation, either version 3 of the License,
6+
// or (at your option) any later version.
7+
//
8+
// The libevm additions are distributed in the hope that they will be useful,
9+
// but WITHOUT ANY WARRANTY; without even the implied warranty of
10+
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
11+
// General Public License for more details.
12+
//
13+
// You should have received a copy of the GNU Lesser General Public License
14+
// along with the go-ethereum library. If not, see
15+
// <http://www.gnu.org/licenses/>.
16+
17+
package state
18+
19+
import (
20+
"github.com/ethereum/go-ethereum/common"
21+
"github.com/ethereum/go-ethereum/core/types"
22+
)
23+
24+
// GetExtra returns the extra payload from the [types.StateAccount] associated
25+
// with the address, or a zero-value `SA` if not found. The
26+
// [types.ExtraPayloads] MUST be sourced from [types.RegisterExtras].
27+
func GetExtra[SA any](s *StateDB, p types.ExtraPayloads[SA], addr common.Address) SA {
28+
stateObject := s.getStateObject(addr)
29+
if stateObject != nil {
30+
return p.FromStateAccount(&stateObject.data)
31+
}
32+
var zero SA
33+
return zero
34+
}
35+
36+
// SetExtra sets the extra payload for the address. See [GetExtra] for details.
37+
func SetExtra[SA any](s *StateDB, p types.ExtraPayloads[SA], addr common.Address, extra SA) {
38+
stateObject := s.getOrNewStateObject(addr)
39+
if stateObject != nil {
40+
setExtraOnObject(stateObject, p, addr, extra)
41+
}
42+
}
43+
44+
func setExtraOnObject[SA any](s *stateObject, p types.ExtraPayloads[SA], addr common.Address, extra SA) {
45+
s.db.journal.append(extraChange[SA]{
46+
payloads: p,
47+
account: &addr,
48+
prev: p.FromStateAccount(&s.data),
49+
})
50+
p.SetOnStateAccount(&s.data, extra)
51+
}
52+
53+
// extraChange is a [journalEntry] for [SetExtra] / [setExtraOnObject].
54+
type extraChange[SA any] struct {
55+
payloads types.ExtraPayloads[SA]
56+
account *common.Address
57+
prev SA
58+
}
59+
60+
func (e extraChange[SA]) dirtied() *common.Address { return e.account }
61+
62+
func (e extraChange[SA]) revert(s *StateDB) {
63+
e.payloads.SetOnStateAccount(&s.getStateObject(*e.account).data, e.prev)
64+
}

core/state/state.libevm_test.go

Lines changed: 172 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,172 @@
1+
// Copyright 2024 the libevm authors.
2+
//
3+
// The libevm additions to go-ethereum are free software: you can redistribute
4+
// them and/or modify them under the terms of the GNU Lesser General Public License
5+
// as published by the Free Software Foundation, either version 3 of the License,
6+
// or (at your option) any later version.
7+
//
8+
// The libevm additions are distributed in the hope that they will be useful,
9+
// but WITHOUT ANY WARRANTY; without even the implied warranty of
10+
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
11+
// General Public License for more details.
12+
//
13+
// You should have received a copy of the GNU Lesser General Public License
14+
// along with the go-ethereum library. If not, see
15+
// <http://www.gnu.org/licenses/>.
16+
17+
package state_test
18+
19+
import (
20+
"fmt"
21+
"reflect"
22+
"testing"
23+
24+
"github.com/google/go-cmp/cmp"
25+
"github.com/stretchr/testify/assert"
26+
"github.com/stretchr/testify/require"
27+
28+
"github.com/ethereum/go-ethereum/common"
29+
"github.com/ethereum/go-ethereum/core/rawdb"
30+
"github.com/ethereum/go-ethereum/core/state"
31+
"github.com/ethereum/go-ethereum/core/state/snapshot"
32+
"github.com/ethereum/go-ethereum/core/types"
33+
"github.com/ethereum/go-ethereum/ethdb/memorydb"
34+
"github.com/ethereum/go-ethereum/libevm/ethtest"
35+
"github.com/ethereum/go-ethereum/triedb"
36+
)
37+
38+
func TestGetSetExtra(t *testing.T) {
39+
type accountExtra struct {
40+
// Data is a pointer to test deep copying.
41+
Data *[]byte // MUST be exported; I spent 20 minutes investigating failing tests because I'm an idiot
42+
}
43+
44+
types.TestOnlyClearRegisteredExtras()
45+
t.Cleanup(types.TestOnlyClearRegisteredExtras)
46+
// Just as its Data field is a pointer, the registered type is a pointer to
47+
// test deep copying.
48+
payloads := types.RegisterExtras[*accountExtra]()
49+
50+
rng := ethtest.NewPseudoRand(42)
51+
addr := rng.Address()
52+
nonce := rng.Uint64()
53+
balance := rng.Uint256()
54+
buf := rng.Bytes(8)
55+
extra := &accountExtra{Data: &buf}
56+
57+
views := newWithSnaps(t)
58+
stateDB := views.newStateDB(t, types.EmptyRootHash)
59+
60+
assert.Nilf(t, state.GetExtra(stateDB, payloads, addr), "state.GetExtra() returns zero-value %T if before account creation", extra)
61+
stateDB.CreateAccount(addr)
62+
stateDB.SetNonce(addr, nonce)
63+
stateDB.SetBalance(addr, balance)
64+
assert.Nilf(t, state.GetExtra(stateDB, payloads, addr), "state.GetExtra() returns zero-value %T if after account creation but before SetExtra()", extra)
65+
state.SetExtra(stateDB, payloads, addr, extra)
66+
require.Equal(t, extra, state.GetExtra(stateDB, payloads, addr), "state.GetExtra() immediately after SetExtra()")
67+
68+
root, err := stateDB.Commit(1, false) // arbitrary block number
69+
require.NoErrorf(t, err, "%T.Commit(1, false)", stateDB)
70+
require.NotEqualf(t, types.EmptyRootHash, root, "root hash returned by %T.Commit() is not the empty root", stateDB)
71+
72+
t.Run(fmt.Sprintf("retrieve from %T", views.snaps), func(t *testing.T) {
73+
iter, err := views.snaps.AccountIterator(root, common.Hash{})
74+
require.NoErrorf(t, err, "%T.AccountIterator(...)", views.snaps)
75+
defer iter.Release()
76+
77+
require.Truef(t, iter.Next(), "%T.Next() (i.e. at least one account)", iter)
78+
require.NoErrorf(t, iter.Error(), "%T.Error()", iter)
79+
80+
t.Run("types.FullAccount()", func(t *testing.T) {
81+
got, err := types.FullAccount(iter.Account())
82+
require.NoErrorf(t, err, "types.FullAccount(%T.Account())", iter)
83+
84+
want := &types.StateAccount{
85+
Nonce: nonce,
86+
Balance: balance,
87+
Root: types.EmptyRootHash,
88+
CodeHash: types.EmptyCodeHash[:],
89+
}
90+
payloads.SetOnStateAccount(want, extra)
91+
92+
if diff := cmp.Diff(want, got); diff != "" {
93+
t.Errorf("types.FullAccount(%T.Account()) diff (-want +got):\n%s", iter, diff)
94+
}
95+
})
96+
97+
require.Falsef(t, iter.Next(), "%T.Next() after first account (i.e. only one)", iter)
98+
})
99+
100+
t.Run(fmt.Sprintf("retrieve from new %T", stateDB), func(t *testing.T) {
101+
s := views.newStateDB(t, root)
102+
assert.Equalf(t, nonce, s.GetNonce(addr), "%T.GetNonce()", s)
103+
assert.Equalf(t, balance, s.GetBalance(addr), "%T.GetBalance()", s)
104+
assert.Equal(t, extra, state.GetExtra(s, payloads, addr), "state.GetExtra()")
105+
})
106+
107+
t.Run("reverting to snapshot", func(t *testing.T) {
108+
s := views.newStateDB(t, root)
109+
snap := s.Snapshot()
110+
111+
oldExtra := extra
112+
buf := append(*oldExtra.Data, rng.Bytes(8)...)
113+
newExtra := &accountExtra{Data: &buf}
114+
115+
state.SetExtra(s, payloads, addr, newExtra)
116+
assert.Equalf(t, newExtra, state.GetExtra(s, payloads, addr), "state.GetExtra() after overwriting with new value")
117+
s.RevertToSnapshot(snap)
118+
assert.Equalf(t, oldExtra, state.GetExtra(s, payloads, addr), "state.GetExtra() after reverting to snapshot")
119+
})
120+
121+
t.Run(fmt.Sprintf("%T.Copy()", stateDB), func(t *testing.T) {
122+
require.Equalf(t, reflect.Pointer, reflect.TypeOf(extra).Kind(), "extra-payload type")
123+
require.Equalf(t, reflect.Pointer, reflect.TypeOf(extra.Data).Kind(), "extra-payload field")
124+
125+
orig := views.newStateDB(t, root)
126+
cp := orig.Copy()
127+
128+
oldExtra := extra
129+
buf := append(*oldExtra.Data, rng.Bytes(8)...)
130+
newExtra := &accountExtra{Data: &buf}
131+
132+
assert.Equalf(t, oldExtra, state.GetExtra(orig, payloads, addr), "GetExtra([original %T]) before setting", orig)
133+
assert.Equalf(t, oldExtra, state.GetExtra(cp, payloads, addr), "GetExtra([copy of %T]) returns the same payload", orig)
134+
state.SetExtra(orig, payloads, addr, newExtra)
135+
assert.Equalf(t, newExtra, state.GetExtra(orig, payloads, addr), "GetExtra([original %T]) returns overwritten payload", orig)
136+
assert.Equalf(t, oldExtra, state.GetExtra(cp, payloads, addr), "GetExtra([copy of %T]) returns original payload despite overwriting on original", orig)
137+
})
138+
}
139+
140+
// stateViews are different ways to access the same data.
141+
type stateViews struct {
142+
snaps *snapshot.Tree
143+
database state.Database
144+
}
145+
146+
func (v stateViews) newStateDB(t *testing.T, root common.Hash) *state.StateDB {
147+
t.Helper()
148+
s, err := state.New(root, v.database, v.snaps)
149+
require.NoError(t, err, "state.New()")
150+
return s
151+
}
152+
153+
func newWithSnaps(t *testing.T) stateViews {
154+
t.Helper()
155+
empty := types.EmptyRootHash
156+
kvStore := memorydb.New()
157+
ethDB := rawdb.NewDatabase(kvStore)
158+
snaps, err := snapshot.New(
159+
snapshot.Config{
160+
CacheSize: 16, // Mb (arbitrary but non-zero)
161+
},
162+
kvStore,
163+
triedb.NewDatabase(ethDB, nil),
164+
empty,
165+
)
166+
require.NoError(t, err, "snapshot.New()")
167+
168+
return stateViews{
169+
snaps: snaps,
170+
database: state.NewDatabase(ethDB),
171+
}
172+
}

0 commit comments

Comments
 (0)