Skip to content

Commit 4532029

Browse files
authored
blockdao.md (#150)
1 parent 3cc0bbc commit 4532029

File tree

2 files changed

+104
-0
lines changed

2 files changed

+104
-0
lines changed

designdoc/blockdao.jpg

58.5 KB
Loading

designdoc/blockdao.md

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
# BlockDAO
2+
BlockDAO manages data access to the blockchain, for example reading a raw data block, querying a transaction by hash, and committing a block to the blockchain
3+
4+
The blockchain data consist of multiple block files (chain.db, chain-00000001.db, etc), the state trie db file (trie.db), and the index db (index.db)
5+
6+
We'll be focusing on block file in the following
7+
8+
## Legacy file (before db split activation at Ithaca height)
9+
Each db file is a key-value db storing raw data in multiple buckets, using *block hash as the key*
10+
1. block header in bucket named "bhr"
11+
2. block body in bucket named "bbd"
12+
3. block footer in bucket named "bfr"
13+
4. block receipt in bucket named "rpt"
14+
15+
In particular, the very first db file (`chain.db`) stores the additional information:
16+
1. the height and hash of the tip block is stored in bucket named "blk"
17+
2. the height/hash mapping of all blocks in bucket named "h2h"
18+
3. transaction log of all blocks in bucket named "syl"
19+
20+
When committing a block, 2 things happen sequentially:
21+
1. block data are written into corresponding db file (like chain-00000001.db)
22+
2. height/hash of the new block, height/hash mapping, and transaction log are written to `chain.db`
23+
24+
## New file (after db split activation)
25+
The request of a new file format design comes from 2 observations:
26+
27+
- Storing the height/hash mapping of all blocks in the first file (chain.db) has led to dependency of the BlockDAO service on this special file, which is a dependency we want to remove
28+
- Using hash as primary key and breaking a block into 3 parts has brought about the following issues:
29+
1) it costs 3 DB reads to fetch a block
30+
2) it consumed more storage space. Earlier testing result shows that using block height as (single incrementing) key and storing the whole block can reduce file size by 30% (10GB chain.db reduced to 7GB using new file format)
31+
32+
The new file is still a key-value db, but *using block height as the key*
33+
1. the height/hash mapping, and transaction log are written in the file itself (to remove dependency on `chain.db`)
34+
2. in addition to height/hash of tip block, we also store the height of the starting block in this file. Doing so allows us to quickly know if a block is stored within a particular db file (starting height <= height <= tip height)
35+
36+
With these adjustments, each block db file is autonomous, meaning it can serve block/transaction query in itself, without having to rely on any other special db or index db
37+
38+
Here's the comparison
39+
40+
File | Primary key | Height/hash mapping | Transaction log | Start height
41+
--- | --- | :---: | :---: | :---:
42+
Legacy | block hash | No (except `chain.db') | No (except `chain.db') | No
43+
New | block height | Yes | Yes | Yes
44+
45+
## Starting the chain soley from state DB
46+
Given the chain db size steadily increasing (today about 30GB), it could become curbersome that a node has to carry on all the history files for it to work.
47+
Now with the help of autonomous db file restructure, we want to achieve a more flexible and lightweight configuration:
48+
49+
1. chain db are broken into multiple data files with user-defined segment size (default 4GB)
50+
2. build the intelligence into BlockDAO, such that a node is able to start up and running from any block db file, or even without a block db file (in which case BlockDAO will create a new one and start from there)
51+
52+
Here are 3 examples:
53+
54+
1. node starts from `chain-00000002.db` which is the latest db file, node continues to add blocks, creating new file `chain-00000003.db` once the current file size grows to defined segment size
55+
2. node starts without any chain db file. BlockDAO will create new file `chain.db` and starts adding blocks into it. Once the file size grows to defined segment size, a new file `chain-00000001.db` will be created
56+
3. node starts from `chain-00000002.db` which has height 500. The next block comes in with height = 1000, BlockDAO will create a new file `chain-00000003.db` and starts adding blocks into it. Once the file size grows to defined segment size, a new file `chain-00000004.db` will be created
57+
58+
In example 3 above, blocks 501~1000 are missing, we might consider improving blocksync module's functionality to reconcile this kind of data missing/inconsistency. This could be another topic for enhancement
59+
60+
## Managing legacy and new files in BlockDAO
61+
In order to handle each individual db file we abstract a FileDAO interface, which contains API to read/write block/action in current BlockDAO interface
62+
```go
63+
FileDAO interface {
64+
Start(ctx context.Context) error
65+
Stop(ctx context.Context) error
66+
Height() (uint64, error)
67+
GetBlockHash(uint64) (hash.Hash256, error)
68+
GetBlockHeight(hash.Hash256) (uint64, error)
69+
GetBlock(hash.Hash256) (*block.Block, error)
70+
GetBlockByHeight(uint64) (*block.Block, error)
71+
GetReceipts(uint64) ([]*action.Receipt, error)
72+
ContainsTransactionLog() bool
73+
TransactionLogs(uint64) (*iotextypes.TransactionLogs, error)
74+
PutBlock(context.Context, *block.Block) error
75+
DeleteTipBlock() error
76+
}
77+
```
78+
79+
and a FileDAONew interface for the new db file
80+
81+
```go
82+
FileDAONew interface {
83+
FileDAO
84+
Bottom() (uint64, error)
85+
ContainsHeight(uint64) bool
86+
}
87+
```
88+
89+
the fileDAO object to implement the interface
90+
91+
```go
92+
// fileDAO implements FileDAO
93+
fileDAO struct {
94+
currFd FileDAO
95+
legacyFd FileDAO
96+
newFd map[uint64]FileDAONew
97+
}
98+
```
99+
100+
1. legacyFd is the interface that manages **all** legacy files
101+
2. newFd is a map of FileDAONew interface, each of which points to **one** new file
102+
3. currFd points to the newest db file (that commit block should write to)
103+
104+
![BlockDAO](/designdoc/blockdao.jpg "BlockDAO example")

0 commit comments

Comments
 (0)