Skip to content

Commit 4473ca0

Browse files
authored
feat: Partial bucket (#3401)
1 parent 3594aee commit 4473ca0

7 files changed

Lines changed: 389 additions & 43 deletions

File tree

core/block_transaction.go

Lines changed: 0 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,9 @@
11
package core
22

33
import (
4-
"bytes"
54
"iter"
6-
"slices"
75

86
"github.com/NethermindEth/juno/core/indexed"
9-
"github.com/NethermindEth/juno/encoder"
107
)
118

129
type BlockTransactionsIndexes struct {
@@ -94,22 +91,3 @@ func (b *BlockTransactions) Transactions() indexed.LazySlice[Transaction] {
9491
func (b *BlockTransactions) Receipts() indexed.LazySlice[*TransactionReceipt] {
9592
return indexed.NewLazySlice[*TransactionReceipt](b.Indexes.Receipts, b.Data)
9693
}
97-
98-
type BlockTransactionsSerializer struct{}
99-
100-
func (BlockTransactionsSerializer) Marshal(value *BlockTransactions) ([]byte, error) {
101-
var buf bytes.Buffer
102-
if err := encoder.NewEncoder(&buf).Encode(value.Indexes); err != nil {
103-
return nil, err
104-
}
105-
if _, err := buf.Write(value.Data); err != nil {
106-
return nil, err
107-
}
108-
return buf.Bytes(), nil
109-
}
110-
111-
func (BlockTransactionsSerializer) Unmarshal(data []byte, value *BlockTransactions) error {
112-
remaining, err := encoder.UnmarshalFirst(data, &value.Indexes)
113-
value.Data = slices.Clone(remaining)
114-
return err
115-
}
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
package core
2+
3+
import (
4+
"bytes"
5+
"slices"
6+
7+
"github.com/NethermindEth/juno/encoder"
8+
)
9+
10+
type BlockTransactionsSerializer struct{}
11+
12+
func (BlockTransactionsSerializer) Marshal(value *BlockTransactions) ([]byte, error) {
13+
var buf bytes.Buffer
14+
if err := encoder.NewEncoder(&buf).Encode(value.Indexes); err != nil {
15+
return nil, err
16+
}
17+
if _, err := buf.Write(value.Data); err != nil {
18+
return nil, err
19+
}
20+
return buf.Bytes(), nil
21+
}
22+
23+
func (BlockTransactionsSerializer) Unmarshal(data []byte, value *BlockTransactions) error {
24+
partial := blockTransactionsPartialSerializer[extractAll, struct{}, BlockTransactions]{}
25+
return partial.UnmarshalPartial(struct{}{}, data, value)
26+
}
27+
28+
type blockTransactionsExtractor[S, T any] interface {
29+
~struct{}
30+
extract(*BlockTransactions, S) (T, error)
31+
}
32+
33+
type extractTransaction struct{}
34+
35+
func (extractTransaction) extract(b *BlockTransactions, subKey int) (Transaction, error) {
36+
return b.Transactions().Get(subKey)
37+
}
38+
39+
type extractReceipt struct{}
40+
41+
func (extractReceipt) extract(b *BlockTransactions, subKey int) (*TransactionReceipt, error) {
42+
return b.Receipts().Get(subKey)
43+
}
44+
45+
type extractAllTransactions struct{}
46+
47+
func (extractAllTransactions) extract(b *BlockTransactions, _ struct{}) ([]Transaction, error) {
48+
return b.Transactions().All()
49+
}
50+
51+
type extractAllReceipts struct{}
52+
53+
func (extractAllReceipts) extract(b *BlockTransactions, _ struct{}) ([]*TransactionReceipt, error) {
54+
return b.Receipts().All()
55+
}
56+
57+
type extractAll struct{}
58+
59+
func (extractAll) extract(b *BlockTransactions, _ struct{}) (BlockTransactions, error) {
60+
return BlockTransactions{
61+
Indexes: b.Indexes,
62+
Data: slices.Clone(b.Data),
63+
}, nil
64+
}
65+
66+
type blockTransactionsPartialSerializer[E blockTransactionsExtractor[S, T], S, T any] struct{}
67+
68+
func (blockTransactionsPartialSerializer[E, S, T]) UnmarshalPartial(
69+
subKey S,
70+
data []byte,
71+
value *T,
72+
) error {
73+
var blockTransactions BlockTransactions
74+
remaining, err := encoder.UnmarshalFirst(data, &blockTransactions.Indexes)
75+
if err != nil {
76+
return err
77+
}
78+
blockTransactions.Data = remaining
79+
*value, err = E{}.extract(&blockTransactions, subKey)
80+
return err
81+
}
82+
83+
var (
84+
BlockTransactionsTransactionPartialSerializer = blockTransactionsPartialSerializer[
85+
extractTransaction,
86+
int,
87+
Transaction,
88+
]{}
89+
BlockTransactionsReceiptPartialSerializer = blockTransactionsPartialSerializer[
90+
extractReceipt,
91+
int,
92+
*TransactionReceipt,
93+
]{}
94+
BlockTransactionsAllTransactionsPartialSerializer = blockTransactionsPartialSerializer[
95+
extractAllTransactions,
96+
struct{},
97+
[]Transaction,
98+
]{}
99+
BlockTransactionsAllReceiptsPartialSerializer = blockTransactionsPartialSerializer[
100+
extractAllReceipts,
101+
struct{},
102+
[]*TransactionReceipt,
103+
]{}
104+
)

core/block_transaction_test.go

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77
"github.com/NethermindEth/juno/adapters/testutils"
88
"github.com/NethermindEth/juno/core"
99
"github.com/NethermindEth/juno/core/indexed"
10+
"github.com/NethermindEth/juno/db/typed/partial"
1011
"github.com/NethermindEth/juno/encoder"
1112
_ "github.com/NethermindEth/juno/encoder/registry"
1213
"github.com/fxamacker/cbor/v2"
@@ -77,6 +78,19 @@ func TestNewBlockTransactionsFromIterators(t *testing.T) {
7778
assertBlockTransactions(t, blockTransactions, transactions, receipts)
7879
}
7980

81+
func assertPartialSerializer[E partial.PartialSerializer[S, T], S, T any](
82+
t *testing.T,
83+
serializer E,
84+
subKey S,
85+
expected T,
86+
serialised []byte,
87+
) {
88+
t.Helper()
89+
var deserialized T
90+
require.NoError(t, serializer.UnmarshalPartial(subKey, serialised, &deserialized))
91+
require.Equal(t, expected, deserialized)
92+
}
93+
8094
func TestBlockTransactionsSerializer(t *testing.T) {
8195
transactions := testutils.GetCoreTransactions(t, transactionCount)
8296
receipts := testutils.GetCoreReceipts(t, transactionCount)
@@ -90,4 +104,48 @@ func TestBlockTransactionsSerializer(t *testing.T) {
90104
require.NoError(t, core.BlockTransactionsSerializer{}.Unmarshal(serialised, &deserialized))
91105

92106
assertBlockTransactions(t, deserialized, transactions, receipts)
107+
108+
t.Run("BlockTransactionsTransactionPartialSerializer", func(t *testing.T) {
109+
for i := range transactionCount {
110+
assertPartialSerializer(
111+
t,
112+
core.BlockTransactionsTransactionPartialSerializer,
113+
i,
114+
transactions[i],
115+
serialised,
116+
)
117+
}
118+
})
119+
120+
t.Run("BlockTransactionsReceiptPartialSerializer", func(t *testing.T) {
121+
for i := range transactionCount {
122+
assertPartialSerializer(
123+
t,
124+
core.BlockTransactionsReceiptPartialSerializer,
125+
i,
126+
receipts[i],
127+
serialised,
128+
)
129+
}
130+
})
131+
132+
t.Run("BlockTransactionsAllTransactionsPartialSerializer", func(t *testing.T) {
133+
assertPartialSerializer(
134+
t,
135+
core.BlockTransactionsAllTransactionsPartialSerializer,
136+
struct{}{},
137+
transactions,
138+
serialised,
139+
)
140+
})
141+
142+
t.Run("BlockTransactionsAllReceiptsPartialSerializer", func(t *testing.T) {
143+
assertPartialSerializer(
144+
t,
145+
core.BlockTransactionsAllReceiptsPartialSerializer,
146+
struct{}{},
147+
receipts,
148+
serialised,
149+
)
150+
})
93151
}

core/transaction_layout.go

Lines changed: 4 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -28,11 +28,7 @@ func (l TransactionLayout) TransactionByBlockAndIndex(
2828
) (Transaction, error) {
2929
switch l {
3030
case TransactionLayoutCombined:
31-
blockTransactions, err := BlockTransactionsBucket.Get(r, blockNumber)
32-
if err != nil {
33-
return nil, err
34-
}
35-
return blockTransactions.Transactions().Get(int(index))
31+
return BlockTransactionsTransactionPartialBucket.Get(r, blockNumber, int(index))
3632

3733
case TransactionLayoutPerTx:
3834
key := db.BlockNumIndexKey{
@@ -54,11 +50,7 @@ func (l TransactionLayout) ReceiptByBlockAndIndex(
5450
) (*TransactionReceipt, error) {
5551
switch l {
5652
case TransactionLayoutCombined:
57-
blockTransactions, err := BlockTransactionsBucket.Get(r, blockNumber)
58-
if err != nil {
59-
return nil, err
60-
}
61-
return blockTransactions.Receipts().Get(int(index))
53+
return BlockTransactionsReceiptPartialBucket.Get(r, blockNumber, int(index))
6254

6355
case TransactionLayoutPerTx:
6456
key := db.BlockNumIndexKey{
@@ -83,11 +75,7 @@ func (l TransactionLayout) TransactionsByBlockNumber(
8375
) ([]Transaction, error) {
8476
switch l {
8577
case TransactionLayoutCombined:
86-
blockTransactions, err := BlockTransactionsBucket.Get(r, blockNum)
87-
if err != nil {
88-
return nil, err
89-
}
90-
return blockTransactions.Transactions().All()
78+
return BlockTransactionsAllTransactionsPartialBucket.Get(r, blockNum, struct{}{})
9179

9280
case TransactionLayoutPerTx:
9381
var transactions []Transaction
@@ -144,11 +132,7 @@ func (l TransactionLayout) ReceiptsByBlockNumber(
144132
) ([]*TransactionReceipt, error) {
145133
switch l {
146134
case TransactionLayoutCombined:
147-
blockTransactions, err := BlockTransactionsBucket.Get(r, blockNum)
148-
if err != nil {
149-
return nil, err
150-
}
151-
return blockTransactions.Receipts().All()
135+
return BlockTransactionsAllReceiptsPartialBucket.Get(r, blockNum, struct{}{})
152136

153137
case TransactionLayoutPerTx:
154138
var receipts []*TransactionReceipt

core/typed_buckets.go

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"github.com/NethermindEth/juno/db"
55
"github.com/NethermindEth/juno/db/typed"
66
"github.com/NethermindEth/juno/db/typed/key"
7+
"github.com/NethermindEth/juno/db/typed/partial"
78
"github.com/NethermindEth/juno/db/typed/prefix"
89
"github.com/NethermindEth/juno/db/typed/value"
910
)
@@ -157,7 +158,6 @@ var ClassCasmHashMetadataBucket = typed.NewBucket(
157158
)
158159

159160
// Bucket 40: Block number (uint64) -> Block transactions (BlockTransactions)
160-
161161
var BlockTransactionsBucket = prefix.NewPrefixedBucket(
162162
typed.NewBucket(
163163
db.BlockTransactions,
@@ -166,3 +166,23 @@ var BlockTransactionsBucket = prefix.NewPrefixedBucket(
166166
),
167167
prefix.Prefix(key.Uint64, prefix.End[BlockTransactions]()),
168168
)
169+
170+
var BlockTransactionsTransactionPartialBucket = partial.NewPartialBucket(
171+
BlockTransactionsBucket.Bucket,
172+
BlockTransactionsTransactionPartialSerializer,
173+
)
174+
175+
var BlockTransactionsReceiptPartialBucket = partial.NewPartialBucket(
176+
BlockTransactionsBucket.Bucket,
177+
BlockTransactionsReceiptPartialSerializer,
178+
)
179+
180+
var BlockTransactionsAllTransactionsPartialBucket = partial.NewPartialBucket(
181+
BlockTransactionsBucket.Bucket,
182+
BlockTransactionsAllTransactionsPartialSerializer,
183+
)
184+
185+
var BlockTransactionsAllReceiptsPartialBucket = partial.NewPartialBucket(
186+
BlockTransactionsBucket.Bucket,
187+
BlockTransactionsAllReceiptsPartialSerializer,
188+
)

db/typed/partial/partial.go

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
package partial
2+
3+
import (
4+
"github.com/NethermindEth/juno/db"
5+
"github.com/NethermindEth/juno/db/typed"
6+
"github.com/NethermindEth/juno/db/typed/key"
7+
"github.com/NethermindEth/juno/db/typed/value"
8+
)
9+
10+
type PartialSerializer[K, V any] interface {
11+
~struct{}
12+
UnmarshalPartial(subKey K, data []byte, value *V) error
13+
}
14+
15+
type PartialBucket[K, K2, V any, KS key.Serializer[K], VS PartialSerializer[K2, V]] struct {
16+
db.Bucket
17+
}
18+
19+
func NewPartialBucket[
20+
K, K2, V, V2 any,
21+
KS key.Serializer[K],
22+
VS value.Serializer[V],
23+
V2S PartialSerializer[K2, V2],
24+
](
25+
bucket typed.Bucket[K, V, KS, VS],
26+
valueSerializer V2S,
27+
) PartialBucket[K, K2, V2, KS, V2S] {
28+
return PartialBucket[K, K2, V2, KS, V2S]{
29+
Bucket: bucket.Bucket,
30+
}
31+
}
32+
33+
func (b PartialBucket[K, K2, V, KS, VS]) Get(
34+
database db.KeyValueReader,
35+
key K,
36+
subKey K2,
37+
) (V, error) {
38+
var value V
39+
err := database.Get(b.Key(KS{}.Marshal(key)), func(data []byte) error {
40+
return VS{}.UnmarshalPartial(subKey, data, &value)
41+
})
42+
return value, err
43+
}

0 commit comments

Comments
 (0)