Skip to content

Commit

Permalink
Implement StoreAllToReplica
Browse files Browse the repository at this point in the history
Doing ForEach in the deferred contract might become expensive when the
state grows big. So we introduce StoreAllToReplica that makes a
"lightweight" copy of the trie and then applies the state changes. It
still makes copies of key/values but only those that are waiting to be
committed to a new block.
  • Loading branch information
kc1212 committed Jul 23, 2019
1 parent 1981bfa commit 84b6a1d
Show file tree
Hide file tree
Showing 3 changed files with 26 additions and 20 deletions.
25 changes: 5 additions & 20 deletions byzcoin/contract_deferred.go
Original file line number Diff line number Diff line change
Expand Up @@ -233,21 +233,6 @@ func (c *contractDeferred) Invoke(rst ReadOnlyStateTrie, inst Instruction, coins
// method like the "processOneTx" one because it involved quite a lot
// of changes and would bring more complexity compared to the benefits.

// In the following we are creating a new StagingStateTrie from the
// readonly state try by copying the data.
nonce, err2 := rst.GetNonce()
if err2 != nil {
return nil, nil, errors.New("couldn't get the nonce: " + err2.Error())
}
sst, err2 := newMemStagingStateTrie(nonce)
if err != nil {
return nil, nil, errors.New("Failed to created stagingStateTrie: " + err2.Error())
}
err = rst.ForEach(sst.Set)
if err != nil {
return nil, nil, errors.New("couldn't make a copy of readOnlyStateTrie: " + err.Error())
}

instructionIDs := make([][]byte, len(c.DeferredData.ProposedTransaction.Instructions))

for i, proposedInstr := range c.DeferredData.ProposedTransaction.Instructions {
Expand Down Expand Up @@ -281,27 +266,27 @@ func (c *contractDeferred) Invoke(rst ReadOnlyStateTrie, inst Instruction, coins
cwr.SetRegistry(c.contracts)
}

err = contract.VerifyDeferredInstruction(sst, proposedInstr, c.DeferredData.InstructionHashes[i])
err = contract.VerifyDeferredInstruction(rst, proposedInstr, c.DeferredData.InstructionHashes[i])
if err != nil {
return nil, nil, fmt.Errorf("verifying the instruction failed: %s", err)
}

var stateChanges []StateChange
switch instructionType {
case SpawnType:
stateChanges, _, err = contract.Spawn(sst, proposedInstr, coins)
stateChanges, _, err = contract.Spawn(rst, proposedInstr, coins)
case InvokeType:
stateChanges, _, err = contract.Invoke(sst, proposedInstr, coins)
stateChanges, _, err = contract.Invoke(rst, proposedInstr, coins)
case DeleteType:
stateChanges, _, err = contract.Delete(sst, proposedInstr, coins)
stateChanges, _, err = contract.Delete(rst, proposedInstr, coins)

}

if err != nil {
return nil, nil, fmt.Errorf("error while executing an instruction: %s", err)
}

err = sst.StoreAll(stateChanges)
rst, err = rst.StoreAllToReplica(stateChanges)
if err != nil {
return nil, nil, fmt.Errorf("error while storing state changes: %s", err)
}
Expand Down
4 changes: 4 additions & 0 deletions byzcoin/contracts/coins_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -321,6 +321,10 @@ func (ct cvTest) GetNonce() ([]byte, error) {
return nil, errors.New("not implemented")
}

func (ct cvTest) StoreAllToReplica(scs byzcoin.StateChanges) (byzcoin.ReadOnlyStateTrie, error) {
return nil, errors.New("not implemented")
}

func (ct cvTest) setSignatureCounter(id string, v uint64) {
key := sha256.Sum256([]byte("signercounter_" + id))
verBuf := make([]byte, 8)
Expand Down
17 changes: 17 additions & 0 deletions byzcoin/statetrie.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"bytes"
"encoding/binary"
"errors"

"go.dedis.ch/cothority/v3/byzcoin/trie"
"go.dedis.ch/cothority/v3/darc"
"go.etcd.io/bbolt"
Expand All @@ -25,6 +26,10 @@ type ReadOnlyStateTrie interface {
// ForEach calls the callback function on every key/value pair in the
// trie, which does not include the metadata.
ForEach(func(k, v []byte) error) error
// StoreAllToReplica creates a copy of the read-only trie and applies
// the state changes to the copy. The implementation should make sure
// that the original read-only trie is not be modified.
StoreAllToReplica(StateChanges) (ReadOnlyStateTrie, error)
}

// stagingStateTrie is a wrapper around trie.StagingTrie that allows for use in
Expand Down Expand Up @@ -90,6 +95,14 @@ func (t *stagingStateTrie) GetIndex() int {
return int(index)
}

func (t *stagingStateTrie) StoreAllToReplica(scs StateChanges) (ReadOnlyStateTrie, error) {
newTrie := t.Clone()
if err := newTrie.StoreAll(scs); err != nil {
return nil, err
}
return newTrie, nil
}

const trieIndexKey = "trieIndexKey"

// stateTrie is a wrapper around trie.Trie that support the storage of an
Expand Down Expand Up @@ -204,6 +217,10 @@ func (t *stateTrie) MakeStagingStateTrie() *stagingStateTrie {
}
}

func (t *stateTrie) StoreAllToReplica(scs StateChanges) (ReadOnlyStateTrie, error) {
return nil, errors.New("unsupported operation")
}

// newMemStagingStateTrie creates an in-memory StagingStateTrie.
func newMemStagingStateTrie(nonce []byte) (*stagingStateTrie, error) {
memTrie, err := trie.NewTrie(trie.NewMemDB(), nonce)
Expand Down

0 comments on commit 84b6a1d

Please sign in to comment.