Skip to content

Commit

Permalink
Store block commitments in the DB
Browse files Browse the repository at this point in the history
  • Loading branch information
omerfirmak committed Aug 2, 2023
1 parent b48dc47 commit e73440e
Show file tree
Hide file tree
Showing 7 changed files with 91 additions and 30 deletions.
54 changes: 48 additions & 6 deletions blockchain/blockchain.go
Original file line number Diff line number Diff line change
Expand Up @@ -309,7 +309,9 @@ func (b *Blockchain) SetL1Head(update *core.L1Head) error {
}

// Store takes a block and state update and performs sanity checks before putting in the database.
func (b *Blockchain) Store(block *core.Block, stateUpdate *core.StateUpdate, newClasses map[felt.Felt]core.Class) error {
func (b *Blockchain) Store(block *core.Block, blockCommitments *core.BlockCommitments,
stateUpdate *core.StateUpdate, newClasses map[felt.Felt]core.Class,
) error {
return b.database.Update(func(txn db.Transaction) error {
if err := verifyBlock(txn, block); err != nil {
return err
Expand All @@ -333,6 +335,10 @@ func (b *Blockchain) Store(block *core.Block, stateUpdate *core.StateUpdate, new
return err
}

if err := storeBlockCommitments(txn, block.Number, blockCommitments); err != nil {
return err
}

if err := txn.Delete(db.Pending.Key()); err != nil {
return err
}
Expand Down Expand Up @@ -377,6 +383,39 @@ func verifyBlock(txn db.Transaction, block *core.Block) error {
return nil
}

func storeBlockCommitments(txn db.Transaction, blockNumber uint64, commitments *core.BlockCommitments) error {
numBytes := core.MarshalBlockNumber(blockNumber)

commitmentBytes, err := encoder.Marshal(commitments)
if err != nil {
return err
}

return txn.Set(db.BlockCommitments.Key(numBytes), commitmentBytes)
}

func (b *Blockchain) BlockCommitmentsByNumber(blockNumber uint64) (*core.BlockCommitments, error) {
var commitments *core.BlockCommitments
return commitments, b.database.View(func(txn db.Transaction) error {
var err error
commitments, err = blockCommitmentsByNumber(txn, blockNumber)
return err
})
}

func blockCommitmentsByNumber(txn db.Transaction, blockNumber uint64) (*core.BlockCommitments, error) {
numBytes := core.MarshalBlockNumber(blockNumber)

var commitments *core.BlockCommitments
if err := txn.Get(db.BlockCommitments.Key(numBytes), func(val []byte) error {
commitments = new(core.BlockCommitments)
return encoder.Unmarshal(val, commitments)
}); err != nil {
return nil, err
}
return commitments, nil
}

// StoreBlockHeader stores the given block in the database.
// The db storage for blocks is maintained by two buckets as follows:
//
Expand Down Expand Up @@ -774,11 +813,14 @@ func (b *Blockchain) revertHead(txn db.Transaction) error {
genesisBlock := blockNumber == 0

// remove block header
if err = txn.Delete(db.BlockHeadersByNumber.Key(numBytes)); err != nil {
return err
}
if err = txn.Delete(db.BlockHeaderNumbersByHash.Key(header.Hash.Marshal())); err != nil {
return err
for _, key := range [][]byte{
db.BlockHeadersByNumber.Key(numBytes),
db.BlockHeaderNumbersByHash.Key(header.Hash.Marshal()),
db.BlockCommitments.Key(numBytes),
} {
if err = txn.Delete(key); err != nil {
return err
}
}
if !genesisBlock {
var newHeader *core.Header
Expand Down
56 changes: 37 additions & 19 deletions blockchain/blockchain_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ import (
"github.com/stretchr/testify/require"
)

var emptyCommitments = core.BlockCommitments{}

func TestNew(t *testing.T) {
client := feeder.NewTestClient(t, utils.MAINNET)
gw := adaptfeeder.New(client)
Expand All @@ -37,7 +39,7 @@ func TestNew(t *testing.T) {

testDB := pebble.NewMemTest()
chain := blockchain.New(testDB, utils.MAINNET, log)
assert.NoError(t, chain.Store(block0, stateUpdate0, nil))
assert.NoError(t, chain.Store(block0, &emptyCommitments, stateUpdate0, nil))

chain = blockchain.New(testDB, utils.MAINNET, log)
b, err := chain.Head()
Expand All @@ -64,7 +66,7 @@ func TestHeight(t *testing.T) {

testDB := pebble.NewMemTest()
chain := blockchain.New(testDB, utils.MAINNET, log)
assert.NoError(t, chain.Store(block0, stateUpdate0, nil))
assert.NoError(t, chain.Store(block0, &emptyCommitments, stateUpdate0, nil))

chain = blockchain.New(testDB, utils.MAINNET, log)
height, err := chain.Height()
Expand All @@ -84,7 +86,7 @@ func TestBlockByNumberAndHash(t *testing.T) {
update, err := gw.StateUpdate(context.Background(), 0)
require.NoError(t, err)

require.NoError(t, chain.Store(block, update, nil))
require.NoError(t, chain.Store(block, &emptyCommitments, update, nil))

storedByNumber, err := chain.BlockByNumber(block.Number)
require.NoError(t, err)
Expand Down Expand Up @@ -133,27 +135,27 @@ func TestVerifyBlock(t *testing.T) {

t.Run("error if version is invalid", func(t *testing.T) {
mainnetBlock0.ProtocolVersion = "notasemver"
require.Error(t, chain.Store(mainnetBlock0, mainnetStateUpdate0, nil))
require.Error(t, chain.Store(mainnetBlock0, &emptyCommitments, mainnetStateUpdate0, nil))
})

t.Run("needs padding", func(t *testing.T) {
mainnetBlock0.ProtocolVersion = "99.0" // should be padded to "99.0.0"
require.EqualError(t, chain.Store(mainnetBlock0, mainnetStateUpdate0, nil), "unsupported block version")
require.EqualError(t, chain.Store(mainnetBlock0, &emptyCommitments, mainnetStateUpdate0, nil), "unsupported block version")
})

t.Run("needs truncating", func(t *testing.T) {
mainnetBlock0.ProtocolVersion = "99.0.0.0" // last 0 digit should be ignored
require.EqualError(t, chain.Store(mainnetBlock0, mainnetStateUpdate0, nil), "unsupported block version")
require.EqualError(t, chain.Store(mainnetBlock0, &emptyCommitments, mainnetStateUpdate0, nil), "unsupported block version")
})

t.Run("greater than supportedStarknetVersion", func(t *testing.T) {
mainnetBlock0.ProtocolVersion = "99.0.0"
require.EqualError(t, chain.Store(mainnetBlock0, mainnetStateUpdate0, nil), "unsupported block version")
require.EqualError(t, chain.Store(mainnetBlock0, &emptyCommitments, mainnetStateUpdate0, nil), "unsupported block version")
})

t.Run("no error with no version string", func(t *testing.T) {
mainnetBlock0.ProtocolVersion = ""
require.NoError(t, chain.Store(mainnetBlock0, mainnetStateUpdate0, nil))
require.NoError(t, chain.Store(mainnetBlock0, &emptyCommitments, mainnetStateUpdate0, nil))
})

t.Run("error if difference between incoming block number and head is not 1",
Expand Down Expand Up @@ -184,7 +186,7 @@ func TestSanityCheckNewHeight(t *testing.T) {
mainnetStateUpdate0, err := gw.StateUpdate(context.Background(), 0)
require.NoError(t, err)

require.NoError(t, chain.Store(mainnetBlock0, mainnetStateUpdate0, nil))
require.NoError(t, chain.Store(mainnetBlock0, &emptyCommitments, mainnetStateUpdate0, nil))

t.Run("error when block hash does not match state update's block hash", func(t *testing.T) {
mainnetBlock1, err := gw.BlockByNumber(context.Background(), 1)
Expand Down Expand Up @@ -219,7 +221,7 @@ func TestStore(t *testing.T) {

t.Run("add block to empty blockchain", func(t *testing.T) {
chain := blockchain.New(pebble.NewMemTest(), utils.MAINNET, log)
require.NoError(t, chain.Store(block0, stateUpdate0, nil))
require.NoError(t, chain.Store(block0, &emptyCommitments, stateUpdate0, nil))

headBlock, err := chain.Head()
require.NoError(t, err)
Expand All @@ -245,8 +247,8 @@ func TestStore(t *testing.T) {
require.NoError(t, err)

chain := blockchain.New(pebble.NewMemTest(), utils.MAINNET, log)
require.NoError(t, chain.Store(block0, stateUpdate0, nil))
require.NoError(t, chain.Store(block1, stateUpdate1, nil))
require.NoError(t, chain.Store(block0, &emptyCommitments, stateUpdate0, nil))
require.NoError(t, chain.Store(block1, &emptyCommitments, stateUpdate1, nil))

headBlock, err := chain.Head()
require.NoError(t, err)
Expand Down Expand Up @@ -279,7 +281,10 @@ func TestTransactionAndReceipt(t *testing.T) {
su, err := gw.StateUpdate(context.Background(), i)
require.NoError(t, err)

require.NoError(t, chain.Store(b, su, nil))
require.NoError(t, chain.Store(b, &core.BlockCommitments{
TransactionCommitment: new(felt.Felt).SetUint64(i),
EventCommitment: new(felt.Felt).SetUint64(2 * i),
}, su, nil))
}

t.Run("GetTransactionByBlockNumberAndIndex returns error if transaction does not exist", func(t *testing.T) {
Expand Down Expand Up @@ -335,6 +340,19 @@ func TestTransactionAndReceipt(t *testing.T) {
})
}
})

t.Run("BlockCommitments returns expected values", func(t *testing.T) {
for i := uint64(0); i < 3; i++ {
t.Run(fmt.Sprintf("mainnet block %v", i), func(t *testing.T) {
commitments, err := chain.BlockCommitmentsByNumber(i)
require.NoError(t, err)
require.Equal(t, &core.BlockCommitments{
TransactionCommitment: new(felt.Felt).SetUint64(i),
EventCommitment: new(felt.Felt).SetUint64(2 * i),
}, commitments)
})
}
})
}

func TestState(t *testing.T) {
Expand All @@ -359,7 +377,7 @@ func TestState(t *testing.T) {
su, err := gw.StateUpdate(context.Background(), i)
require.NoError(t, err)

require.NoError(t, chain.Store(block, su, nil))
require.NoError(t, chain.Store(block, &emptyCommitments, su, nil))
existingBlockHash = block.Hash
}

Expand Down Expand Up @@ -420,7 +438,7 @@ func TestEvents(t *testing.T) {
require.NoError(t, err)

if b.Number < 6 {
require.NoError(t, chain.Store(b, s, nil))
require.NoError(t, chain.Store(b, &emptyCommitments, s, nil))
} else {
require.NoError(t, chain.StorePending(&blockchain.Pending{
Block: b,
Expand Down Expand Up @@ -539,7 +557,7 @@ func TestRevert(t *testing.T) {
su, err := gw.StateUpdate(context.Background(), i)
require.NoError(t, err)

require.NoError(t, chain.Store(b, su, nil))
require.NoError(t, chain.Store(b, &emptyCommitments, su, nil))
}

require.NoError(t, chain.RevertHead())
Expand Down Expand Up @@ -647,7 +665,7 @@ func TestPending(t *testing.T) {
})

t.Run("storing genesis as an accepted block should clear pending", func(t *testing.T) {
require.NoError(t, chain.Store(b, su, nil))
require.NoError(t, chain.Store(b, &emptyCommitments, su, nil))
_, pErr := chain.Pending()
require.ErrorIs(t, pErr, db.ErrKeyNotFound)
})
Expand Down Expand Up @@ -723,7 +741,7 @@ func TestSubscribeNewHeads(t *testing.T) {
require.NoError(t, err)
su0, err := gw.StateUpdate(context.Background(), 0)
require.NoError(t, err)
require.NoError(t, chain.Store(block0, su0, nil))
require.NoError(t, chain.Store(block0, &core.BlockCommitments{}, su0, nil))

sink := make(chan *core.Header, 2048)
chain.SubscribeNewHeads(sink)
Expand All @@ -733,7 +751,7 @@ func TestSubscribeNewHeads(t *testing.T) {
require.NoError(t, err)
su1, err := gw.StateUpdate(context.Background(), 1)
require.NoError(t, err)
require.NoError(t, chain.Store(block1, su1, nil))
require.NoError(t, chain.Store(block1, &core.BlockCommitments{}, su1, nil))

got1, notClosed := <-sink
require.True(t, notClosed)
Expand Down
1 change: 1 addition & 0 deletions db/buckets.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ const (
L1Height
SchemaVersion
Pending
BlockCommitments
)

// Key flattens a prefix and series of byte arrays into a single []byte.
Expand Down
2 changes: 1 addition & 1 deletion migration/migration_pkg_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ func TestRecalculateBloomFilters(t *testing.T) {
require.NoError(t, err)

b.EventsBloom = nil
require.NoError(t, chain.Store(b, su, nil))
require.NoError(t, chain.Store(b, &core.BlockCommitments{}, su, nil))
}

require.NoError(t, testdb.Update(recalculateBloomFilters))
Expand Down
2 changes: 1 addition & 1 deletion rpc/handlers_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1591,7 +1591,7 @@ func TestEvents(t *testing.T) {
require.NoError(t, err)

if b.Number < 6 {
require.NoError(t, chain.Store(b, s, nil))
require.NoError(t, chain.Store(b, &core.BlockCommitments{}, s, nil))
} else {
b.Hash = nil
b.GlobalStateRoot = nil
Expand Down
4 changes: 2 additions & 2 deletions sync/sync.go
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ func (s *Synchronizer) verifierTask(ctx context.Context, block *core.Block, stat
newClasses map[felt.Felt]core.Class, resetStreams context.CancelFunc,
) stream.Callback {
timer := prometheus.NewTimer(s.opTimers.WithLabelValues(opVerifyLabel))
_, err := s.Blockchain.SanityCheckNewHeight(block, stateUpdate, newClasses)
commitments, err := s.Blockchain.SanityCheckNewHeight(block, stateUpdate, newClasses)
timer.ObserveDuration()
return func() {
select {
Expand All @@ -172,7 +172,7 @@ func (s *Synchronizer) verifierTask(ctx context.Context, block *core.Block, stat
return
}
timer := prometheus.NewTimer(s.opTimers.WithLabelValues(opStoreLabel))
err = s.Blockchain.Store(block, stateUpdate, newClasses)
err = s.Blockchain.Store(block, commitments, stateUpdate, newClasses)
timer.ObserveDuration()

if err != nil {
Expand Down
2 changes: 1 addition & 1 deletion sync/sync_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ func TestSyncBlocks(t *testing.T) {
require.NoError(t, err)
s0, err := gw.StateUpdate(context.Background(), 0)
require.NoError(t, err)
require.NoError(t, bc.Store(b0, s0, nil))
require.NoError(t, bc.Store(b0, &core.BlockCommitments{}, s0, nil))

synchronizer := sync.New(bc, gw, log, time.Duration(0))
ctx, cancel := context.WithTimeout(context.Background(), timeout)
Expand Down

0 comments on commit e73440e

Please sign in to comment.