Skip to content

Commit

Permalink
Work on db replay
Browse files Browse the repository at this point in the history
This PR does the following for 'bcadmin db replay':
- add all blocks to the skipchain.db, so that contracts using 'ReadOnlySkipchain' work
- by default doesn't verify the forward link signature of blocks, as this is very costly,
and can be supposed to be correct if its in 'cached.db'
- use a memory state trie instead of a disk state trie when replaying -> much faster
  • Loading branch information
ineiti committed May 20, 2020
1 parent d097fd5 commit 53b07dc
Show file tree
Hide file tree
Showing 8 changed files with 199 additions and 319 deletions.
2 changes: 1 addition & 1 deletion byzcoin/bcadmin/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -229,7 +229,7 @@ and return success:

```bash
bcadmin db catchup cached.db _bcID_ _url_
bcadmin db replay cached.db _bcID_ --continue
bcadmin db replay cached.db _bcID_
```

The `_bcID_` has to be replaced by the hexadecimal representation of the
Expand Down
63 changes: 17 additions & 46 deletions byzcoin/bcadmin/cmd_db.go
Original file line number Diff line number Diff line change
Expand Up @@ -90,12 +90,10 @@ func dbReplay(c *cli.Context) error {
log.Info("Preparing db")
start := *fb.bcID
err = fb.boltDB.Update(func(tx *bbolt.Tx) error {
if !fb.flagReplayCont {
if tx.Bucket(fb.bucketName) != nil {
err := tx.DeleteBucket(fb.bucketName)
if err != nil {
return err
}
if tx.Bucket(fb.bucketName) != nil {
err := tx.DeleteBucket(fb.bucketName)
if err != nil {
return err
}
}
_, err := tx.CreateBucketIfNotExists(fb.bucketName)
Expand All @@ -108,35 +106,15 @@ func dbReplay(c *cli.Context) error {
return xerrors.Errorf("couldn't add bucket: %+v", err)
}

if !fb.flagReplayCont {
_, err = fb.service.ReplayStateDB(fb.boltDB, fb.bucketName, fb.genesis)
if err != nil {
return xerrors.Errorf("couldn't create stateDB: %+v", err)
}
} else {
index, err := fb.service.ReplayStateDB(fb.boltDB, fb.bucketName, nil)
if err != nil {
return xerrors.Errorf("couldn't replay blocks: %+v", err)
}

log.Info("Searching for block with index", index+1)
sb := fb.db.GetByID(start)
for sb != nil && sb.Index < index+1 {
if len(sb.ForwardLink) == 0 {
break
}
sb = fb.db.GetByID(sb.ForwardLink[0].To)
start = sb.Hash
}
if sb.Index <= index {
log.Info("No new blocks available")
return nil
}
}
log.Lvl2("Copying blocks to skipchain's DB")
fb.skipchain.GetDB().DB = fb.db.DB

log.Info("Replaying blocks")
_, err = fb.service.ReplayStateContLog(start,
&sumFetcher{summarizeBlocks: c.Int("summarize"), bff: fb.blockFetcher})
err = fb.service.ReplayState(start, newSumFetcher(c),
byzcoin.ReplayStateOptions{
MaxBlocks: c.Int("blocks"),
VerifyFLSig: c.Bool("verifyFLSig"),
})
if err != nil {
return xerrors.Errorf("couldn't replay blocks: %+v", err)
}
Expand All @@ -147,7 +125,6 @@ func dbReplay(c *cli.Context) error {

type sumFetcher struct {
summarizeBlocks int
bff byzcoin.BlockFetcherFunc
totalTXs int
accepted int
seenBlocks int
Expand All @@ -156,11 +133,12 @@ type sumFetcher struct {
maxTPS float64
maxBlockSize int
totalBlockSize int
verifyFLSig bool
maxBlocks int
}

func (sf sumFetcher) BlockFetcherFunc(sid skipchain.SkipBlockID) (*skipchain.
SkipBlock, error) {
return sf.bff(sid)
func newSumFetcher(c *cli.Context) *sumFetcher {
return &sumFetcher{summarizeBlocks: c.Int("summarize")}
}

func (sf sumFetcher) LogNewBlock(sb *skipchain.SkipBlock) {
Expand Down Expand Up @@ -509,6 +487,7 @@ func dbCheck(c *cli.Context) error {
type fetchBlocks struct {
cl *skipchain.Client
service *byzcoin.Service
skipchain *skipchain.Service
bcID *skipchain.SkipBlockID
local *onet.LocalTest
roster *onet.Roster
Expand All @@ -520,8 +499,6 @@ type fetchBlocks struct {
db *skipchain.SkipBlockDB
bucketName []byte
flagCatchupBatch int
flagReplayBlocks int
flagReplayCont bool
}

func newFetchBlocks(c *cli.Context) (*fetchBlocks,
Expand All @@ -535,13 +512,12 @@ func newFetchBlocks(c *cli.Context) (*fetchBlocks,
local: onet.NewLocalTest(cothority.Suite),
bucketName: []byte("replayStateBucket"),
flagCatchupBatch: c.Int("batch"),
flagReplayBlocks: c.Int("blocks"),
flagReplayCont: c.Bool("continue"),
}

var err error
servers := fb.local.GenServers(1)
fb.service = servers[0].Service(byzcoin.ServiceName).(*byzcoin.Service)
fb.skipchain = servers[0].Service(skipchain.ServiceName).(*skipchain.Service)

log.Info("Opening database", c.Args().First())
fb.db, fb.boltDB, err = fb.openDB(c.Args().First())
Expand Down Expand Up @@ -630,11 +606,6 @@ func (fb *fetchBlocks) addURL(url string) error {
}

func (fb *fetchBlocks) blockFetcher(sib skipchain.SkipBlockID) (*skipchain.SkipBlock, error) {
fb.flagReplayBlocks--
if fb.flagReplayBlocks == 0 {
log.Info("reached end of task")
return nil, nil
}
sb := fb.db.GetByID(sib)
if sb == nil {
return nil, nil
Expand Down
9 changes: 5 additions & 4 deletions byzcoin/bcadmin/commands.go
Original file line number Diff line number Diff line change
Expand Up @@ -656,19 +656,20 @@ var cmds = cli.Commands{
Usage: "Replay a chain and check the global state is consistent",
Action: dbReplay,
Flags: []cli.Flag{
cli.BoolFlag{
Name: "continue, cont",
Usage: "continue an aborted replay",
},
cli.IntFlag{
Name: "blocks",
Usage: "how many blocks to apply",
Value: -1,
},
cli.IntFlag{
Name: "summarize, sum",
Usage: "summarize this many blocks in output",
Value: 1,
},
cli.BoolFlag{
Name: "verifyFLSig",
Usage: "turns on forward-link signature verification",
},
},
},
{
Expand Down
12 changes: 4 additions & 8 deletions byzcoin/bcadmin/test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
# Options:
# -b re-builds bcadmin package

DBG_TEST=2
DBG_TEST=1
DBG_SRV=1
DBG_BCADMIN=2

Expand Down Expand Up @@ -84,15 +84,11 @@ testDbReplay(){
testOK runBA db catchup conode.db $bcID http://localhost:2003
testGrep "Replaying block at index 0" runBA db replay conode.db $bcID

# replay with more than 1 block
testOK runBA mint $bc $key $keyPub 1000
testOK runBA mint $bc $key $keyPub 1000

# replay with more than 1 block
runBA db catchup conode.db $bcID http://localhost:2003
testNGrep "Replaying block at index 0" runBA db replay conode.db $bcID --cont
testReGrep "Replaying block at index 1"
testGrep "Replaying block at index 0" runBA db replay conode.db $bcID
testOK runBA db replay conode.db $bcID --cont
}

testDbMerge(){
Expand Down Expand Up @@ -322,7 +318,7 @@ testAddDarc(){
testGrep "${ID:5:${#ID}-0}" runBA darc show --darc "$ID"

# checks the --shortPrint option
OUTRES=$(runBA darc add --shortPrint)
OUTRES=$(runBA0 darc add --shortPrint)
matchOK "$OUTRES" "darc:[0-9a-f]{64}
\[ed25519:[0-9a-f]{64}\]"
}
Expand Down Expand Up @@ -478,7 +474,7 @@ runBA(){
}

runBA0(){
dbgRun ./bcadmin -c config/ --debug 0 "$@"
./bcadmin -c config/ --debug 0 "$@"
}

testQR() {
Expand Down
1 change: 1 addition & 0 deletions byzcoin/contracts.go
Original file line number Diff line number Diff line change
Expand Up @@ -541,6 +541,7 @@ func (c *contractConfig) Invoke(rst ReadOnlyStateTrie, inst Instruction, coins [
if err != nil {
return nil, nil, xerrors.Errorf("decoding: %v", err)
}

if rst.GetVersion() < VersionViewchange {
// If everything is correctly signed, then we trust it, no need
// to do additional verification.
Expand Down
2 changes: 1 addition & 1 deletion byzcoin/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -2173,7 +2173,7 @@ func (s *Service) createStateChanges(sst *stagingStateTrie, scID skipchain.SkipB
if err != nil {
tx.Accepted = false
txOut = append(txOut, tx)
log.Error(s.ServerIdentity(), err)
log.Warn(s.ServerIdentity(), err)
} else {
// We would like to be able to check if this txn is so big it could never fit into a block,
// and if so, drop it. But we can't with the current API of createStateChanges.
Expand Down
Loading

0 comments on commit 53b07dc

Please sign in to comment.