forked from ethereum/go-ethereum
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
218bde2
commit 2c70f51
Showing
3 changed files
with
322 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,170 @@ | ||
package rawdb | ||
|
||
import ( | ||
"bytes" | ||
"encoding/binary" | ||
"math/big" | ||
|
||
"github.com/scroll-tech/go-ethereum/common" | ||
"github.com/scroll-tech/go-ethereum/core/types" | ||
"github.com/scroll-tech/go-ethereum/ethdb" | ||
"github.com/scroll-tech/go-ethereum/log" | ||
"github.com/scroll-tech/go-ethereum/rlp" | ||
) | ||
|
||
// | ||
func WriteSyncedL1BlockNumber(db ethdb.KeyValueWriter, blockNumber *big.Int) { | ||
value := []byte{0} | ||
if blockNumber != nil { | ||
value = blockNumber.Bytes() | ||
} | ||
if err := db.Put(syncedL1BlockNumberKey, value); err != nil { | ||
log.Crit("Failed to synced L1 block number", "err", err) | ||
} | ||
} | ||
|
||
// | ||
func ReadSyncedL1BlockNumber(db ethdb.Reader) *big.Int { | ||
data, _ := db.Get(syncedL1BlockNumberKey) | ||
if len(data) == 0 { | ||
return nil | ||
} | ||
return new(big.Int).SetBytes(data) | ||
} | ||
|
||
// | ||
func WriteL1Message(db ethdb.KeyValueWriter, msg *types.L1MessageTx) { | ||
bytes, err := rlp.EncodeToBytes(msg) | ||
if err != nil { | ||
log.Crit("Failed to RLP encode L1 message", "err", err) | ||
} | ||
enqueueIndex := msg.Nonce | ||
if err := db.Put(L1MessageKey(enqueueIndex), bytes); err != nil { | ||
log.Crit("Failed to store L1 message", "err", err) | ||
} | ||
} | ||
|
||
// | ||
// TODO: consider writing messages in batches | ||
func WriteL1Messages(db ethdb.KeyValueWriter, msgs []types.L1MessageTx) { | ||
for _, msg := range msgs { | ||
WriteL1Message(db, &msg) | ||
} | ||
} | ||
|
||
// | ||
func ReadL1MessageRLP(db ethdb.Reader, enqueueIndex uint64) rlp.RawValue { | ||
data, err := db.Get(L1MessageKey(enqueueIndex)) | ||
if err != nil { | ||
log.Crit("Failed to load L1 message", "enqueueIndex", enqueueIndex, "err", err) | ||
} | ||
return data | ||
} | ||
|
||
// | ||
func ReadL1Message(db ethdb.Reader, enqueueIndex uint64) *types.L1MessageTx { | ||
data := ReadL1MessageRLP(db, enqueueIndex) | ||
if len(data) == 0 { | ||
return nil | ||
} | ||
msg := new(types.L1MessageTx) | ||
if err := rlp.Decode(bytes.NewReader(data), msg); err != nil { | ||
log.Crit("Invalid L1 message RLP", "enqueueIndex", enqueueIndex, "err", err) | ||
} | ||
return msg | ||
} | ||
|
||
type L1MessageIterator struct { | ||
inner ethdb.Iterator | ||
keyLength int | ||
} | ||
|
||
func IterateL1MessagesFrom(db ethdb.Iteratee, from uint64) L1MessageIterator { | ||
start := encodeEnqueueIndex(from) | ||
it := db.NewIterator(L1MessagePrefix, start) | ||
keyLength := len(L1MessagePrefix) + 8 | ||
|
||
return L1MessageIterator{ | ||
inner: it, | ||
keyLength: keyLength, | ||
} | ||
} | ||
|
||
func (it *L1MessageIterator) Next() bool { | ||
for it.inner.Next() { | ||
key := it.inner.Key() | ||
if len(key) == it.keyLength { | ||
return true | ||
} | ||
} | ||
return false | ||
} | ||
|
||
func (it *L1MessageIterator) EnqueueIndex() uint64 { | ||
key := it.inner.Key() | ||
enqueueIndex := binary.BigEndian.Uint64(key[len(L1MessagePrefix) : len(L1MessagePrefix)+8]) | ||
return enqueueIndex | ||
} | ||
|
||
func (it *L1MessageIterator) L1Message() types.L1MessageTx { | ||
data := it.inner.Value() | ||
msg := types.L1MessageTx{} | ||
if err := rlp.DecodeBytes(data, &msg); err != nil { | ||
log.Crit("Invalid L1 message RLP", "err", err) | ||
} | ||
return msg | ||
} | ||
|
||
func (it *L1MessageIterator) Release() { | ||
it.inner.Release() | ||
} | ||
|
||
// | ||
func ReadLMessagesInRange(db ethdb.Iteratee, first, last uint64) []types.L1MessageTx { | ||
msgs := make([]types.L1MessageTx, 0, last-first+1) | ||
it := IterateL1MessagesFrom(db, first) | ||
defer it.Release() | ||
|
||
for it.Next() { | ||
if it.EnqueueIndex() > last { | ||
break | ||
} | ||
msgs = append(msgs, it.L1Message()) | ||
} | ||
|
||
return msgs | ||
} | ||
|
||
type L1MessagesInBlock struct { | ||
FirstEnqueueIndex uint64 | ||
LastEnqueueIndex uint64 | ||
} | ||
|
||
// | ||
func WriteL1MessagesInBlock(db ethdb.KeyValueWriter, hash common.Hash, entry L1MessagesInBlock) { | ||
bytes, err := rlp.EncodeToBytes(entry) | ||
if err != nil { | ||
log.Crit("Failed to RLP encode L1 messages in block", "err", err) | ||
} | ||
if err := db.Put(L1MessagesInBlockKey(hash), bytes); err != nil { | ||
log.Crit("Failed to store L1 messages in block", "hash", hash, "err", err) | ||
} | ||
} | ||
|
||
// | ||
func ReadL1MessagesInBlock(db ethdb.Reader, hash common.Hash) *L1MessagesInBlock { | ||
data, _ := db.Get(L1MessagesInBlockKey(hash)) | ||
if len(data) == 0 { | ||
return nil | ||
} | ||
var entry L1MessagesInBlock | ||
if err := rlp.DecodeBytes(data, &entry); err != nil { | ||
log.Error("Invalid L1 messages in block RLP", "hash", hash, "blob", data, "err", err) | ||
return nil | ||
} | ||
return &entry | ||
} | ||
|
||
// write messages | ||
// new block received | ||
// set block index: block number => { first_enqueue_index, last_enqueue_index } |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,130 @@ | ||
package rawdb | ||
|
||
import ( | ||
"math/big" | ||
"testing" | ||
|
||
"github.com/scroll-tech/go-ethereum/common" | ||
"github.com/scroll-tech/go-ethereum/core/types" | ||
) | ||
|
||
func TestReadWriteSyncedL1BlockNumber(t *testing.T) { | ||
blockNumbers := []*big.Int{ | ||
big.NewInt(0).SetUint64(1), | ||
big.NewInt(0).SetUint64(1 << 2), | ||
big.NewInt(0).SetUint64(1 << 8), | ||
big.NewInt(0).SetUint64(1 << 16), | ||
big.NewInt(0).SetUint64(1 << 32), | ||
} | ||
|
||
db := NewMemoryDatabase() | ||
for _, num := range blockNumbers { | ||
WriteSyncedL1BlockNumber(db, num) | ||
got := ReadSyncedL1BlockNumber(db) | ||
|
||
if num.Cmp(got) != 0 { | ||
t.Fatal("Block number mismatch") | ||
} | ||
} | ||
} | ||
|
||
func newL1MessageTx(enqueueIndex uint64) types.L1MessageTx { | ||
return types.L1MessageTx{ | ||
Nonce: enqueueIndex, | ||
Gas: 0, | ||
To: nil, | ||
Value: big.NewInt(0), | ||
Data: nil, | ||
Sender: &common.Address{}, | ||
} | ||
} | ||
|
||
func TestReadWriteL1Message(t *testing.T) { | ||
enqueueIndex := uint64(123) | ||
msg := newL1MessageTx(enqueueIndex) | ||
db := NewMemoryDatabase() | ||
WriteL1Message(db, &msg) | ||
|
||
got := ReadL1Message(db, enqueueIndex) | ||
if got == nil || got.Nonce != msg.Nonce { | ||
t.Fatal("L1 message mismatch", "got", got) | ||
} | ||
} | ||
|
||
func TestIterateL1Message(t *testing.T) { | ||
msgs := []types.L1MessageTx{ | ||
newL1MessageTx(100), | ||
newL1MessageTx(101), | ||
newL1MessageTx(103), | ||
newL1MessageTx(200), | ||
newL1MessageTx(1000), | ||
} | ||
|
||
db := NewMemoryDatabase() | ||
WriteL1Messages(db, msgs) | ||
|
||
it := IterateL1MessagesFrom(db, 103) | ||
defer it.Release() | ||
|
||
it.Next() | ||
got := it.L1Message() | ||
if got.Nonce != 103 { | ||
t.Fatal("Invalid result", "nonce", got.Nonce) | ||
} | ||
|
||
it.Next() | ||
got = it.L1Message() | ||
if got.Nonce != 200 { | ||
t.Fatal("Invalid result", "nonce", got.Nonce) | ||
} | ||
|
||
it.Next() | ||
got = it.L1Message() | ||
if got.Nonce != 1000 { | ||
t.Fatal("Invalid result", "nonce", got.Nonce) | ||
} | ||
|
||
finished := it.Next() | ||
if finished { | ||
t.Fatal("Invalid result", "finished", finished) | ||
} | ||
} | ||
|
||
func TestReadL1MessageTxRange(t *testing.T) { | ||
msgs := []types.L1MessageTx{ | ||
newL1MessageTx(100), | ||
newL1MessageTx(101), | ||
newL1MessageTx(103), | ||
newL1MessageTx(200), | ||
newL1MessageTx(1000), | ||
} | ||
|
||
db := NewMemoryDatabase() | ||
WriteL1Messages(db, msgs) | ||
|
||
got := ReadLMessagesInRange(db, 100, 199) | ||
|
||
if len(got) != 3 { | ||
t.Fatal("Invalid length", "length", len(got)) | ||
} | ||
|
||
if got[0].Nonce != 100 || got[1].Nonce != 101 || got[2].Nonce != 103 { | ||
t.Fatal("Invalid result", "got", got) | ||
} | ||
} | ||
|
||
func TestReadWriteL1MessagesInBlock(t *testing.T) { | ||
hash := common.Hash{1} | ||
db := NewMemoryDatabase() | ||
|
||
WriteL1MessagesInBlock(db, hash, L1MessagesInBlock{ | ||
FirstEnqueueIndex: 1, | ||
LastEnqueueIndex: 9, | ||
}) | ||
|
||
got := ReadL1MessagesInBlock(db, hash) | ||
|
||
if got == nil || got.FirstEnqueueIndex != 1 || got.LastEnqueueIndex != 9 { | ||
t.Fatal("Incorrect result", "got", got) | ||
} | ||
} |