consensus: extend payloads with StateRoot info
Create and verify witness after block processing.
This commit is contained in:
parent
edcfdb3bde
commit
10189b6ab3
3 changed files with 58 additions and 4 deletions
|
@ -8,6 +8,7 @@ import (
|
|||
// commit represents dBFT Commit message.
|
||||
type commit struct {
|
||||
signature [signatureSize]byte
|
||||
stateSig [signatureSize]byte
|
||||
}
|
||||
|
||||
// signatureSize is an rfc6989 signature size in bytes
|
||||
|
@ -19,11 +20,13 @@ var _ payload.Commit = (*commit)(nil)
|
|||
// EncodeBinary implements io.Serializable interface.
|
||||
func (c *commit) EncodeBinary(w *io.BinWriter) {
|
||||
w.WriteBytes(c.signature[:])
|
||||
w.WriteBytes(c.stateSig[:])
|
||||
}
|
||||
|
||||
// DecodeBinary implements io.Serializable interface.
|
||||
func (c *commit) DecodeBinary(r *io.BinReader) {
|
||||
r.ReadBytes(c.signature[:])
|
||||
r.ReadBytes(c.stateSig[:])
|
||||
}
|
||||
|
||||
// Signature implements payload.Commit interface.
|
||||
|
|
|
@ -13,6 +13,7 @@ import (
|
|||
"github.com/nspcc-dev/neo-go/pkg/core"
|
||||
coreb "github.com/nspcc-dev/neo-go/pkg/core/block"
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/mempool"
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/state"
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
|
||||
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
||||
"github.com/nspcc-dev/neo-go/pkg/smartcontract"
|
||||
|
@ -135,10 +136,10 @@ func NewService(cfg Config) (Service, error) {
|
|||
dbft.WithGetConsensusAddress(srv.getConsensusAddress),
|
||||
|
||||
dbft.WithNewConsensusPayload(func() payload.ConsensusPayload { p := new(Payload); p.message = &message{}; return p }),
|
||||
dbft.WithNewPrepareRequest(func() payload.PrepareRequest { return new(prepareRequest) }),
|
||||
dbft.WithNewPrepareRequest(srv.newPrepareRequest),
|
||||
dbft.WithNewPrepareResponse(func() payload.PrepareResponse { return new(prepareResponse) }),
|
||||
dbft.WithNewChangeView(func() payload.ChangeView { return new(changeView) }),
|
||||
dbft.WithNewCommit(func() payload.Commit { return new(commit) }),
|
||||
dbft.WithNewCommit(srv.newCommit),
|
||||
dbft.WithNewRecoveryRequest(func() payload.RecoveryRequest { return new(recoveryRequest) }),
|
||||
dbft.WithNewRecoveryMessage(func() payload.RecoveryMessage { return new(recoveryMessage) }),
|
||||
)
|
||||
|
@ -209,6 +210,33 @@ func (s *service) eventLoop() {
|
|||
}
|
||||
}
|
||||
|
||||
func (s *service) newPrepareRequest() payload.PrepareRequest {
|
||||
sr, err := s.Chain.GetStateRoot(s.Chain.BlockHeight())
|
||||
if err != nil {
|
||||
return new(prepareRequest)
|
||||
}
|
||||
return &prepareRequest{
|
||||
proposalStateRoot: sr.MPTRootBase,
|
||||
}
|
||||
}
|
||||
|
||||
func (s *service) newCommit() payload.Commit {
|
||||
for _, p := range s.dbft.Context.PreparationPayloads {
|
||||
if p != nil && p.ViewNumber() == s.dbft.ViewNumber && p.Type() == payload.PrepareRequestType {
|
||||
pr := p.GetPrepareRequest().(*prepareRequest)
|
||||
data := pr.proposalStateRoot.GetSignedPart()
|
||||
sign, err := s.dbft.Priv.Sign(data)
|
||||
if err == nil {
|
||||
var c commit
|
||||
copy(c.stateSig[:], sign)
|
||||
return &c
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
return new(commit)
|
||||
}
|
||||
|
||||
func (s *service) validatePayload(p *Payload) bool {
|
||||
validators := s.getValidators()
|
||||
if int(p.validatorIndex) >= len(validators) {
|
||||
|
@ -350,16 +378,35 @@ func (s *service) processBlock(b block.Block) {
|
|||
s.log.Warn("error on add block", zap.Error(err))
|
||||
}
|
||||
}
|
||||
|
||||
var rb *state.MPTRootBase
|
||||
for _, p := range s.dbft.PreparationPayloads {
|
||||
if p != nil && p.Type() == payload.PrepareRequestType {
|
||||
rb = &p.GetPrepareRequest().(*prepareRequest).proposalStateRoot
|
||||
}
|
||||
}
|
||||
w := s.getWitness(func(p payload.Commit) []byte { return p.(*commit).stateSig[:] })
|
||||
r := &state.MPTRoot{
|
||||
MPTRootBase: *rb,
|
||||
Witness: w,
|
||||
}
|
||||
if err := s.Chain.AddStateRoot(r); err != nil {
|
||||
s.log.Warn("errors while adding state root", zap.Error(err))
|
||||
}
|
||||
}
|
||||
|
||||
func (s *service) getBlockWitness(b *coreb.Block) *transaction.Witness {
|
||||
func (s *service) getBlockWitness(_ *coreb.Block) *transaction.Witness {
|
||||
return s.getWitness(func(p payload.Commit) []byte { return p.Signature() })
|
||||
}
|
||||
|
||||
func (s *service) getWitness(f func(p payload.Commit) []byte) *transaction.Witness {
|
||||
dctx := s.dbft.Context
|
||||
pubs := convertKeys(dctx.Validators)
|
||||
sigs := make(map[*keys.PublicKey][]byte)
|
||||
|
||||
for i := range pubs {
|
||||
if p := dctx.CommitPayloads[i]; p != nil && p.ViewNumber() == dctx.ViewNumber {
|
||||
sigs[pubs[i]] = p.GetCommit().Signature()
|
||||
sigs[pubs[i]] = f(p.GetCommit())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@ package consensus
|
|||
|
||||
import (
|
||||
"github.com/nspcc-dev/dbft/payload"
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/state"
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
|
||||
"github.com/nspcc-dev/neo-go/pkg/io"
|
||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||
|
@ -14,6 +15,7 @@ type prepareRequest struct {
|
|||
transactionHashes []util.Uint256
|
||||
minerTx transaction.Transaction
|
||||
nextConsensus util.Uint160
|
||||
proposalStateRoot state.MPTRootBase
|
||||
}
|
||||
|
||||
var _ payload.PrepareRequest = (*prepareRequest)(nil)
|
||||
|
@ -25,6 +27,7 @@ func (p *prepareRequest) EncodeBinary(w *io.BinWriter) {
|
|||
w.WriteBytes(p.nextConsensus[:])
|
||||
w.WriteArray(p.transactionHashes)
|
||||
p.minerTx.EncodeBinary(w)
|
||||
p.proposalStateRoot.EncodeBinary(w)
|
||||
}
|
||||
|
||||
// DecodeBinary implements io.Serializable interface.
|
||||
|
@ -34,6 +37,7 @@ func (p *prepareRequest) DecodeBinary(r *io.BinReader) {
|
|||
r.ReadBytes(p.nextConsensus[:])
|
||||
r.ReadArray(&p.transactionHashes)
|
||||
p.minerTx.DecodeBinary(r)
|
||||
p.proposalStateRoot.DecodeBinary(r)
|
||||
}
|
||||
|
||||
// Timestamp implements payload.PrepareRequest interface.
|
||||
|
|
Loading…
Reference in a new issue