Skip to content

Commit 44d5295

Browse files
committed
firewood x-chain
Signed-off-by: Joshua Kim <20001595+joshua-kim@users.noreply.github.com>
1 parent 4d07d90 commit 44d5295

File tree

26 files changed

+1594
-176
lines changed

26 files changed

+1594
-176
lines changed

chains/atomic/shared_memory.go

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,10 @@ import (
1010
"github.com/ava-labs/avalanchego/utils"
1111
)
1212

13-
var _ SharedMemory = (*sharedMemory)(nil)
13+
var (
14+
_ SharedMemory = (*sharedMemory)(nil)
15+
_ SharedMemory = (*ReadOnlySharedMemory)(nil)
16+
)
1417

1518
type Requests struct {
1619
RemoveRequests [][]byte `serialize:"true"`
@@ -163,3 +166,44 @@ func (sm *sharedMemory) Apply(requests map[ids.ID]*Requests, batches ...database
163166

164167
return WriteAll(batch, batches...)
165168
}
169+
170+
type ReadOnlySharedMemory struct {
171+
sm SharedMemory
172+
}
173+
174+
func NewReadOnlySharedMemory(sharedMemory SharedMemory) ReadOnlySharedMemory {
175+
return ReadOnlySharedMemory{sm: sharedMemory}
176+
}
177+
178+
func (r ReadOnlySharedMemory) Get(
179+
peerChainID ids.ID,
180+
keys [][]byte,
181+
) (
182+
[][]byte,
183+
error,
184+
) {
185+
return r.sm.Get(peerChainID, keys)
186+
}
187+
188+
func (r ReadOnlySharedMemory) Indexed(
189+
peerChainID ids.ID,
190+
traits [][]byte,
191+
startTrait,
192+
startKey []byte,
193+
limit int,
194+
) ([][]byte, []byte, []byte, error) {
195+
return r.sm.Indexed(
196+
peerChainID,
197+
traits,
198+
startTrait,
199+
startKey,
200+
limit,
201+
)
202+
}
203+
204+
func (r ReadOnlySharedMemory) Apply(
205+
map[ids.ID]*Requests,
206+
...database.Batch,
207+
) error {
208+
return nil
209+
}

database/memdb/db.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ package memdb
55

66
import (
77
"context"
8+
"fmt"
89
"slices"
910
"strings"
1011
"sync"
@@ -38,6 +39,21 @@ func New() *Database {
3839
return NewWithSize(DefaultSize)
3940
}
4041

42+
// Copy returns a Database with the same key-value pairs as db
43+
func Copy(db *Database) (*Database, error) {
44+
db.lock.Lock()
45+
defer db.lock.Unlock()
46+
47+
result := New()
48+
for k, v := range db.db {
49+
if err := result.Put([]byte(k), v); err != nil {
50+
return nil, fmt.Errorf("failed to insert key: %w", err)
51+
}
52+
}
53+
54+
return result, nil
55+
}
56+
4157
// NewWithSize returns a map pre-allocated to the provided size with the
4258
// Database interface methods implemented.
4359
func NewWithSize(size int) *Database {

firewood/firewood.go

Lines changed: 167 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,167 @@
1+
// Copyright (C) 2019-2025, Ava Labs, Inc. All rights reserved.
2+
// See the file LICENSE for licensing terms.
3+
4+
package firewood
5+
6+
import (
7+
"fmt"
8+
9+
"github.com/ava-labs/firewood-go-ethhash/ffi"
10+
11+
"github.com/ava-labs/avalanchego/database"
12+
"github.com/ava-labs/avalanchego/ids"
13+
)
14+
15+
const PrefixDelimiter = '/'
16+
17+
var (
18+
consensusPrefix = []byte("consensus")
19+
heightKey = []byte("height")
20+
appPrefix = []byte("app")
21+
)
22+
23+
type changes struct {
24+
Keys [][]byte
25+
Vals [][]byte
26+
27+
kv map[string][]byte
28+
}
29+
30+
func (c *changes) Put(key []byte, val []byte) {
31+
c.put(Prefix(appPrefix, key), val, false)
32+
}
33+
34+
func (c *changes) Delete(key []byte) {
35+
c.put(Prefix(appPrefix, key), nil, true)
36+
}
37+
38+
func (c *changes) put(key []byte, val []byte, delete bool) {
39+
if val == nil && !delete {
40+
// TODO dont panic
41+
panic("cannot put nil values")
42+
}
43+
44+
c.Keys = append(c.Keys, key)
45+
c.Vals = append(c.Vals, val)
46+
47+
if c.kv == nil {
48+
c.kv = make(map[string][]byte)
49+
}
50+
51+
c.kv[string(key)] = val
52+
}
53+
54+
func (c *changes) Get(key []byte) ([]byte, bool) {
55+
v, ok := c.kv[string(Prefix(appPrefix, key))]
56+
return v, ok
57+
}
58+
59+
type DB struct {
60+
db *ffi.Database
61+
height uint64
62+
// invariant: pending always has a length > 0 due to the inclusion of the
63+
// block height
64+
pending changes
65+
}
66+
67+
func NewDB(path string) (*DB, error) {
68+
db, err := ffi.New(path, ffi.DefaultConfig())
69+
if err != nil {
70+
return nil, fmt.Errorf("opening firewood db: %w", err)
71+
}
72+
73+
var height uint64
74+
75+
heightBytes, err := db.Get(Prefix(consensusPrefix, heightKey))
76+
if heightBytes == nil && err == nil {
77+
height = 0 // TODO weird if
78+
} else if err != nil {
79+
return nil, fmt.Errorf("getting height: %w", err)
80+
} else {
81+
height, err = database.ParseUInt64(heightBytes)
82+
if err != nil {
83+
return nil, fmt.Errorf("parsing height: %w", err)
84+
}
85+
}
86+
87+
return &DB{
88+
db: db,
89+
height: height,
90+
}, nil
91+
}
92+
93+
func (db *DB) Get(key []byte) ([]byte, error) {
94+
if val, ok := db.pending.Get(key); ok {
95+
return val, nil
96+
}
97+
98+
val, err := db.db.Get(key)
99+
if val == nil && err == nil {
100+
return nil, database.ErrNotFound
101+
}
102+
103+
return val, err
104+
}
105+
106+
func (db *DB) Put(key []byte, val []byte) {
107+
db.pending.Put(key, val)
108+
}
109+
110+
func (db *DB) Delete(key []byte) {
111+
db.pending.Delete(key)
112+
}
113+
114+
func (db *DB) Height() uint64 {
115+
return db.height
116+
}
117+
118+
func (db *DB) Root() (ids.ID, error) {
119+
root, err := db.db.Root()
120+
if err != nil {
121+
return ids.ID{}, err
122+
}
123+
124+
return ids.ID(root), nil
125+
}
126+
127+
func (db *DB) Abort() {
128+
db.pending = changes{}
129+
}
130+
131+
func (db *DB) Flush() error {
132+
db.height++
133+
db.pending.Put(
134+
Prefix(consensusPrefix, heightKey),
135+
database.PackUInt64(db.height),
136+
)
137+
138+
p, err := db.db.Propose(db.pending.Keys, db.pending.Vals)
139+
if err != nil {
140+
return fmt.Errorf("proposing changes: %w", err)
141+
}
142+
143+
if err := p.Commit(); err != nil {
144+
return fmt.Errorf("committing changes: %w", err)
145+
}
146+
147+
db.pending = changes{}
148+
return nil
149+
}
150+
151+
func (db *DB) Close() error {
152+
return db.db.Close()
153+
}
154+
155+
// TODO test prefixing
156+
//
157+
// Prefix adds a prefix + delimiter
158+
// prefix must not contain the delimiter
159+
func Prefix(prefix []byte, key []byte) []byte {
160+
k := make([]byte, len(prefix)+len(key))
161+
162+
copy(k, prefix)
163+
k[len(prefix)] = PrefixDelimiter
164+
copy(k[len(prefix)+1:], key)
165+
166+
return k
167+
}

go.mod

Lines changed: 49 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ require (
2222
github.com/StephenButtolph/canoto v0.17.3
2323
github.com/antithesishq/antithesis-sdk-go v0.3.8
2424
github.com/ava-labs/coreth v0.16.0-rc.0
25+
github.com/ava-labs/firewood-go-ethhash/ffi v0.0.13
2526
github.com/ava-labs/libevm v1.13.15-0.20251016142715-1bccf4f2ddb2
2627
github.com/ava-labs/subnet-evm v0.8.1-db-metrics-fix
2728
github.com/btcsuite/btcd/btcutil v1.1.3
@@ -89,7 +90,6 @@ require (
8990
require (
9091
github.com/Microsoft/go-winio v0.6.1 // indirect
9192
github.com/VictoriaMetrics/fastcache v1.12.1 // indirect
92-
github.com/ava-labs/firewood-go-ethhash/ffi v0.0.13 // indirect
9393
github.com/ava-labs/simplex v0.0.0-20250919142550-9cdfff10fd19
9494
github.com/beorn7/perks v1.0.1 // indirect
9595
github.com/bits-and-blooms/bitset v1.20.0 // indirect
@@ -199,6 +199,54 @@ require (
199199
sigs.k8s.io/yaml v1.3.0 // indirect
200200
)
201201

202+
// Exclude all old monolithic genproto versions from 2019-2021 to avoid ambiguous imports
203+
// The split modules (googleapis/rpc, googleapis/api) should be used instead
204+
exclude (
205+
google.golang.org/genproto v0.0.0-20180518175338-11a468237815
206+
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8
207+
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19
208+
google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7
209+
google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb
210+
google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873
211+
google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64
212+
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55
213+
google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51
214+
google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a
215+
google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9
216+
google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1
217+
google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb
218+
google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba
219+
google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150
220+
google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90
221+
google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce
222+
google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63
223+
google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383
224+
google.golang.org/genproto v0.0.0-20200305110556-506484158171
225+
google.golang.org/genproto v0.0.0-20200312145019-da6875a35672
226+
google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940
227+
google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84
228+
google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380
229+
google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884
230+
google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587
231+
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013
232+
google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790
233+
google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f
234+
google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c
235+
google.golang.org/genproto v0.0.0-20200825200019-8632dd797987
236+
google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d
237+
google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb
238+
google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e
239+
google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc
240+
google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d
241+
google.golang.org/genproto v0.0.0-20210222152913-aa3ee6e6a81c
242+
google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb
243+
google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e
244+
google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6
245+
google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1
246+
google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c
247+
google.golang.org/genproto v0.0.0-20210624195500-8bfb893ecb84
248+
)
249+
202250
tool (
203251
github.com/StephenButtolph/canoto/canoto
204252
github.com/onsi/ginkgo/v2/ginkgo

0 commit comments

Comments
 (0)