Skip to content

Commit 216db6c

Browse files
committed
[execution] Improve caching in accessors + simplify code
1 parent e1448e1 commit 216db6c

19 files changed

Lines changed: 519 additions & 1062 deletions

nil/internal/collate/block_listener.go

Lines changed: 7 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -212,15 +212,9 @@ func SetBlockRequestHandler(
212212
}
213213
defer tx.Rollback()
214214

215-
acc := accessor.RawAccess(tx, shardId).
216-
GetBlock().
217-
WithOutTransactions().
218-
WithInTransactions().
219-
WithChildBlocks().
220-
WithConfig()
221-
215+
acc := accessor.RawAccess(tx, shardId)
222216
for id := blockReq.GetId(); ; id++ {
223-
resp, err := acc.ByNumber(types.BlockNumber(id))
217+
resp, err := acc.GetFullBlockByNumber(types.BlockNumber(id))
224218
if err != nil {
225219
if !errors.Is(err, db.ErrKeyNotFound) {
226220
logError(logger, err, "DB error")
@@ -229,11 +223,11 @@ func SetBlockRequestHandler(
229223
}
230224

231225
b := &pb.RawFullBlock{
232-
BlockBytes: resp.Block(),
233-
OutTransactionsBytes: resp.OutTransactions(),
234-
InTransactionsBytes: resp.InTransactions(),
235-
ChildBlocks: pb.PackHashes(resp.ChildBlocks()),
236-
Config: resp.Config(),
226+
BlockBytes: resp.Block,
227+
OutTransactionsBytes: resp.OutTransactions,
228+
InTransactionsBytes: resp.InTransactions,
229+
ChildBlocks: pb.PackHashes(resp.ChildBlocks),
230+
Config: resp.Config,
237231
}
238232

239233
if err := writeBlockToStream(s, b); err != nil {

nil/internal/collate/proposer_test.go

Lines changed: 22 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package collate
22

33
import (
4+
"slices"
45
"testing"
56

67
"github.com/NilFoundation/nil/nil/common"
@@ -97,24 +98,24 @@ func (s *ProposerTestSuite) TestCollator() {
9798
p := newTestProposer(params, pool)
9899
shardId := p.params.ShardId
99100

100-
generateBlock := func() *execution.Proposal {
101+
generateBlock := func() (*execution.Proposal, *execution.BlockGenerationResult) {
101102
proposal := s.generateProposal(p)
102103

103104
tx, err := s.db.CreateRoTx(s.T().Context())
104105
s.Require().NoError(err)
105106
defer tx.Rollback()
106107

107-
block, err := db.ReadBlock(tx, shardId, proposal.PrevBlockHash)
108+
prevBlock, err := db.ReadBlock(tx, shardId, proposal.PrevBlockHash)
108109
s.Require().NoError(err)
109110

110-
blockGenerator, err := execution.NewBlockGenerator(s.T().Context(), params.BlockGeneratorParams, s.db, block)
111+
gen, err := execution.NewBlockGenerator(s.T().Context(), params.BlockGeneratorParams, s.db, prevBlock)
111112
s.Require().NoError(err)
112-
defer blockGenerator.Rollback()
113+
defer gen.Rollback()
113114

114-
_, err = blockGenerator.GenerateBlock(proposal, &types.ConsensusParams{})
115+
block, err := gen.GenerateBlock(proposal, &types.ConsensusParams{})
115116
s.Require().NoError(err)
116117

117-
return proposal
118+
return proposal, block
118119
}
119120

120121
s.Run("GenerateZeroState", func() {
@@ -133,9 +134,9 @@ func (s *ProposerTestSuite) TestCollator() {
133134
pool.Reset()
134135
pool.Add(m1, m2)
135136

136-
proposal := generateBlock()
137-
r1 = s.checkReceipt(shardId, m1)
138-
r2 = s.checkReceipt(shardId, m2)
137+
proposal, res := generateBlock()
138+
r1 = s.checkReceipt(res, m1)
139+
r2 = s.checkReceipt(res, m2)
139140
s.Equal(pool.Txns, proposal.ExternalTxns)
140141

141142
// Each transaction subtracts its value + actual gas used from the balance.
@@ -160,15 +161,13 @@ func (s *ProposerTestSuite) TestCollator() {
160161

161162
balance = balance.Add(r1.Forwarded).Add(r2.Forwarded)
162163
s.Equal(balance, s.getMainBalance())
163-
164-
s.checkSeqno(shardId)
165164
})
166165

167166
s.Run("DoNotProcessDuplicates", func() {
168167
pool.Reset()
169168
pool.Add(m1, m2)
170169

171-
proposal := generateBlock()
170+
proposal, _ := generateBlock()
172171
s.Empty(proposal.ExternalTxns)
173172
s.Empty(proposal.InternalTxns)
174173
s.Empty(proposal.ForwardTxns)
@@ -183,36 +182,17 @@ func (s *ProposerTestSuite) TestCollator() {
183182
pool.Reset()
184183
pool.Add(m)
185184

186-
generateBlock()
187-
s.checkReceipt(shardId, m)
185+
_, res := generateBlock()
186+
s.checkReceipt(res, m)
188187
})
189188

190189
s.Run("Execute", func() {
191190
m := execution.NewExecutionTransaction(to, to, 1, contracts.NewCounterAddCallData(s.T(), 3))
192191
pool.Reset()
193192
pool.Add(m)
194193

195-
generateBlock()
196-
s.checkReceipt(shardId, m)
197-
})
198-
199-
s.Run("CheckRefundsSeqno", func() {
200-
m01 := execution.NewSendMoneyTransaction(s.T(), to, 2)
201-
m02 := execution.NewSendMoneyTransaction(s.T(), to, 3)
202-
pool.Reset()
203-
pool.Add(m01, m02)
204-
205-
// send tokens
206-
generateBlock()
207-
208-
// process internal transactions
209-
generateBlock()
210-
211-
// process refunds
212-
generateBlock()
213-
214-
// check refunds seqnos
215-
s.checkSeqno(shardId)
194+
_, res := generateBlock()
195+
s.checkReceipt(res, m)
216196
})
217197
}
218198

@@ -245,52 +225,16 @@ func (s *ProposerTestSuite) getBalance(shardId types.ShardId, addr types.Address
245225
return acc.Balance
246226
}
247227

248-
func (s *ProposerTestSuite) checkSeqno(shardId types.ShardId) {
249-
s.T().Helper()
250-
251-
tx, err := s.db.CreateRoTx(s.T().Context())
252-
s.Require().NoError(err)
253-
defer tx.Rollback()
254-
255-
sa := execution.NewStateAccessor()
256-
blockHash, err := db.ReadLastBlockHash(tx, shardId)
257-
s.Require().NoError(err)
258-
259-
block, err := sa.Access(tx, shardId).GetBlock().WithInTransactions().WithOutTransactions().ByHash(blockHash)
260-
s.Require().NoError(err)
261-
262-
check := func(txns []*types.Transaction) {
263-
if len(txns) == 0 {
264-
return
265-
}
266-
seqno := txns[0].Seqno
267-
for _, m := range txns {
268-
s.Require().Equal(seqno, m.Seqno)
269-
seqno++
270-
}
271-
}
272-
273-
check(block.InTransactions())
274-
check(block.OutTransactions())
275-
}
276-
277-
func (s *ProposerTestSuite) checkReceipt(shardId types.ShardId, m *types.Transaction) *types.Receipt {
228+
func (s *ProposerTestSuite) checkReceipt(genRes *execution.BlockGenerationResult, m *types.Transaction) *types.Receipt {
278229
s.T().Helper()
279230

280-
tx, err := s.db.CreateRoTx(s.T().Context())
281-
s.Require().NoError(err)
282-
defer tx.Rollback()
283-
284-
sa := execution.NewStateAccessor()
285-
txnData, err := sa.Access(tx, m.From.ShardId()).GetInTransaction().ByHash(m.Hash())
286-
s.Require().NoError(err)
231+
hash := m.Hash()
232+
idx := slices.IndexFunc(genRes.Receipts, func(r *types.Receipt) bool {
233+
return r.TxnHash == hash
234+
})
235+
s.Require().GreaterOrEqual(idx, 0, "receipt not found for transaction %s", hash)
287236

288-
receiptsTrie := execution.NewDbReceiptTrieReader(tx, shardId)
289-
s.Require().NoError(receiptsTrie.SetRootHash(txnData.Block().ReceiptsRoot))
290-
receipt, err := receiptsTrie.Fetch(txnData.Index())
291-
s.Require().NoError(err)
292-
s.Equal(m.Hash(), receipt.TxnHash)
293-
return receipt
237+
return genRes.Receipts[idx]
294238
}
295239

296240
func TestProposer(t *testing.T) {

nil/internal/db/accessors.go

Lines changed: 36 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -3,22 +3,43 @@ package db
33
import (
44
"encoding/binary"
55
"errors"
6+
"fmt"
67
"reflect"
78

89
"github.com/NilFoundation/nil/nil/common"
910
"github.com/NilFoundation/nil/nil/internal/serialization"
1011
"github.com/NilFoundation/nil/nil/internal/types"
1112
)
1213

13-
// todo: return errors
14+
type prettyKey interface {
15+
fmt.Stringer
16+
Bytes() []byte
17+
}
18+
19+
func Get(tx RoTx, table TableName, key prettyKey) ([]byte, error) {
20+
data, err := tx.Get(table, key.Bytes())
21+
if err != nil {
22+
return nil, fmt.Errorf("%w: key=%s", err, key)
23+
}
24+
return data, nil
25+
}
26+
27+
func GetFromShard(tx RoTx, shardId types.ShardId, table ShardedTableName, key prettyKey) ([]byte, error) {
28+
data, err := tx.GetFromShard(shardId, table, key.Bytes())
29+
if err != nil {
30+
return nil, fmt.Errorf("%w: key=%s", err, key)
31+
}
32+
return data, nil
33+
}
34+
1435
func readDecodable[
1536
T interface {
1637
~*S
1738
serialization.NilUnmarshaler
1839
},
1940
S any,
2041
](tx RoTx, table ShardedTableName, shardId types.ShardId, hash common.Hash) (*S, error) {
21-
data, err := tx.GetFromShard(shardId, table, hash.Bytes())
42+
data, err := GetFromShard(tx, shardId, table, hash)
2243
if err != nil {
2344
return nil, err
2445
}
@@ -30,25 +51,15 @@ func readDecodable[
3051
return decoded, nil
3152
}
3253

33-
func writeRawKeyEncodable[
34-
T interface {
35-
serialization.NilMarshaler
36-
},
37-
](tx RwTx, tableName ShardedTableName, shardId types.ShardId, key []byte, value T) error {
38-
data, err := value.MarshalNil()
54+
func writeEncodable[T serialization.NilMarshaler](
55+
tx RwTx, tableName ShardedTableName, shardId types.ShardId, hash common.Hash, obj T,
56+
) error {
57+
data, err := obj.MarshalNil()
3958
if err != nil {
4059
return err
4160
}
4261

43-
return tx.PutToShard(shardId, tableName, key, data)
44-
}
45-
46-
func writeEncodable[
47-
T interface {
48-
serialization.NilMarshaler
49-
},
50-
](tx RwTx, tableName ShardedTableName, shardId types.ShardId, hash common.Hash, obj T) error {
51-
return writeRawKeyEncodable(tx, tableName, shardId, hash.Bytes(), obj)
62+
return tx.PutToShard(shardId, tableName, hash.Bytes(), data)
5263
}
5364

5465
func ReadVersionInfo(tx RoTx) (*types.VersionInfo, error) {
@@ -88,7 +99,7 @@ func ReadBlock(tx RoTx, shardId types.ShardId, hash common.Hash) (*types.Block,
8899
}
89100

90101
func ReadBlockBytes(tx RoTx, shardId types.ShardId, hash common.Hash) ([]byte, error) {
91-
return tx.GetFromShard(shardId, blockTable, hash.Bytes())
102+
return GetFromShard(tx, shardId, blockTable, hash)
92103
}
93104

94105
func ReadLastBlock(tx RoTx, shardId types.ShardId) (*types.Block, common.Hash, error) {
@@ -105,7 +116,7 @@ func ReadLastBlock(tx RoTx, shardId types.ShardId) (*types.Block, common.Hash, e
105116

106117
func ReadCollatorState(tx RoTx, shardId types.ShardId) (types.CollatorState, error) {
107118
res := types.CollatorState{}
108-
buf, err := tx.Get(collatorStateTable, shardId.Bytes())
119+
buf, err := Get(tx, collatorStateTable, shardId)
109120
if err != nil {
110121
return res, err
111122
}
@@ -125,7 +136,7 @@ func WriteCollatorState(tx RwTx, shardId types.ShardId, state types.CollatorStat
125136
}
126137

127138
func ReadLastBlockHash(tx RoTx, shardId types.ShardId) (common.Hash, error) {
128-
h, err := tx.Get(LastBlockTable, shardId.Bytes())
139+
h, err := Get(tx, LastBlockTable, shardId)
129140
return common.BytesToHash(h), err
130141
}
131142

@@ -140,7 +151,7 @@ func WriteBlockTimestamp(tx RwTx, shardId types.ShardId, blockHash common.Hash,
140151
}
141152

142153
func ReadBlockTimestamp(tx RoTx, shardId types.ShardId, blockHash common.Hash) (uint64, error) {
143-
value, err := tx.GetFromShard(shardId, blockTimestampTable, blockHash.Bytes())
154+
value, err := GetFromShard(tx, shardId, blockTimestampTable, blockHash)
144155
if err != nil {
145156
return 0, err
146157
}
@@ -156,7 +167,7 @@ func WriteError(tx RwTx, txnHash common.Hash, errMsg string) error {
156167
}
157168

158169
func ReadError(tx RoTx, txnHash common.Hash) (string, error) {
159-
res, err := tx.Get(errorByTransactionHashTable, txnHash.Bytes())
170+
res, err := Get(tx, errorByTransactionHashTable, txnHash)
160171
if err != nil {
161172
return "", err
162173
}
@@ -168,14 +179,14 @@ func WriteCode(tx RwTx, shardId types.ShardId, hash common.Hash, code types.Code
168179
}
169180

170181
func ReadCode(tx RoTx, shardId types.ShardId, hash common.Hash) (types.Code, error) {
171-
if hash == types.EmptyCodeHash {
182+
if hash.Empty() {
172183
return types.Code{}, nil
173184
}
174-
return tx.GetFromShard(shardId, codeTable, hash.Bytes())
185+
return GetFromShard(tx, shardId, codeTable, hash)
175186
}
176187

177188
func ReadBlockHashByNumber(tx RoTx, shardId types.ShardId, blockNumber types.BlockNumber) (common.Hash, error) {
178-
blockHash, err := tx.GetFromShard(shardId, BlockHashByNumberIndex, blockNumber.Bytes())
189+
blockHash, err := GetFromShard(tx, shardId, BlockHashByNumberIndex, blockNumber)
179190
return common.BytesToHash(blockHash), err
180191
}
181192

nil/internal/db/badger.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"bytes"
55
"context"
66
"errors"
7+
"fmt"
78
"io"
89
"runtime"
910
"sync"
@@ -226,7 +227,7 @@ func (tx *BadgerRwTx) Put(tableName TableName, key, value []byte) error {
226227
func (tx *BadgerRoTx) Get(tableName TableName, key []byte) ([]byte, error) {
227228
item, err := tx.tx.Get(MakeKey(tableName, key))
228229
if errors.Is(err, badger.ErrKeyNotFound) {
229-
return nil, ErrKeyNotFound
230+
return nil, fmt.Errorf("%w: table %s", ErrKeyNotFound, tableName)
230231
}
231232
if err != nil {
232233
return nil, err

nil/internal/execution/block_cache.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,17 +35,17 @@ func getHashFn(es *ExecutionState, ref *types.Block) func(n uint64) (common.Hash
3535
lastKnownHash := cache[len(cache)-1]
3636

3737
for {
38-
data, err := es.shardAccessor.GetBlock().ByHash(lastKnownHash)
38+
b, err := es.shardAccessor.GetBlockByHash(lastKnownHash)
3939
if errors.Is(err, db.ErrKeyNotFound) {
4040
break
4141
}
4242
if err != nil {
4343
return common.EmptyHash, err
4444
}
4545

46-
cache = append(cache, data.Block().PrevBlock)
47-
lastKnownHash = data.Block().PrevBlock
48-
lastKnownNumber := data.Block().Id.Uint64() - 1
46+
cache = append(cache, b.PrevBlock)
47+
lastKnownHash = b.PrevBlock
48+
lastKnownNumber := b.Id.Uint64() - 1
4949
if n == lastKnownNumber {
5050
return lastKnownHash, nil
5151
}

nil/internal/execution/block_generator.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ type BlockGenerationResult struct {
6060
InTxnHashes []common.Hash
6161
OutTxns []*types.Transaction
6262
OutTxnHashes []common.Hash
63+
Receipts []*types.Receipt
6364
ConfigParams map[string][]byte
6465

6566
Counters *BlockGeneratorCounters

0 commit comments

Comments
 (0)