mirror of
https://github.com/nspcc-dev/neo-go.git
synced 2024-12-05 03:58:23 +00:00
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.
|
// commit represents dBFT Commit message.
|
||||||
type commit struct {
|
type commit struct {
|
||||||
signature [signatureSize]byte
|
signature [signatureSize]byte
|
||||||
|
stateSig [signatureSize]byte
|
||||||
}
|
}
|
||||||
|
|
||||||
// signatureSize is an rfc6989 signature size in bytes
|
// signatureSize is an rfc6989 signature size in bytes
|
||||||
|
@ -19,11 +20,13 @@ var _ payload.Commit = (*commit)(nil)
|
||||||
// EncodeBinary implements io.Serializable interface.
|
// EncodeBinary implements io.Serializable interface.
|
||||||
func (c *commit) EncodeBinary(w *io.BinWriter) {
|
func (c *commit) EncodeBinary(w *io.BinWriter) {
|
||||||
w.WriteBytes(c.signature[:])
|
w.WriteBytes(c.signature[:])
|
||||||
|
w.WriteBytes(c.stateSig[:])
|
||||||
}
|
}
|
||||||
|
|
||||||
// DecodeBinary implements io.Serializable interface.
|
// DecodeBinary implements io.Serializable interface.
|
||||||
func (c *commit) DecodeBinary(r *io.BinReader) {
|
func (c *commit) DecodeBinary(r *io.BinReader) {
|
||||||
r.ReadBytes(c.signature[:])
|
r.ReadBytes(c.signature[:])
|
||||||
|
r.ReadBytes(c.stateSig[:])
|
||||||
}
|
}
|
||||||
|
|
||||||
// Signature implements payload.Commit interface.
|
// Signature implements payload.Commit interface.
|
||||||
|
|
|
@ -13,6 +13,7 @@ import (
|
||||||
"github.com/nspcc-dev/neo-go/pkg/core"
|
"github.com/nspcc-dev/neo-go/pkg/core"
|
||||||
coreb "github.com/nspcc-dev/neo-go/pkg/core/block"
|
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/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/core/transaction"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/smartcontract"
|
"github.com/nspcc-dev/neo-go/pkg/smartcontract"
|
||||||
|
@ -135,10 +136,10 @@ func NewService(cfg Config) (Service, error) {
|
||||||
dbft.WithGetConsensusAddress(srv.getConsensusAddress),
|
dbft.WithGetConsensusAddress(srv.getConsensusAddress),
|
||||||
|
|
||||||
dbft.WithNewConsensusPayload(func() payload.ConsensusPayload { p := new(Payload); p.message = &message{}; return p }),
|
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.WithNewPrepareResponse(func() payload.PrepareResponse { return new(prepareResponse) }),
|
||||||
dbft.WithNewChangeView(func() payload.ChangeView { return new(changeView) }),
|
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.WithNewRecoveryRequest(func() payload.RecoveryRequest { return new(recoveryRequest) }),
|
||||||
dbft.WithNewRecoveryMessage(func() payload.RecoveryMessage { return new(recoveryMessage) }),
|
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 {
|
func (s *service) validatePayload(p *Payload) bool {
|
||||||
validators := s.getValidators()
|
validators := s.getValidators()
|
||||||
if int(p.validatorIndex) >= len(validators) {
|
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))
|
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
|
dctx := s.dbft.Context
|
||||||
pubs := convertKeys(dctx.Validators)
|
pubs := convertKeys(dctx.Validators)
|
||||||
sigs := make(map[*keys.PublicKey][]byte)
|
sigs := make(map[*keys.PublicKey][]byte)
|
||||||
|
|
||||||
for i := range pubs {
|
for i := range pubs {
|
||||||
if p := dctx.CommitPayloads[i]; p != nil && p.ViewNumber() == dctx.ViewNumber {
|
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 (
|
import (
|
||||||
"github.com/nspcc-dev/dbft/payload"
|
"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/core/transaction"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/io"
|
"github.com/nspcc-dev/neo-go/pkg/io"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||||
|
@ -14,6 +15,7 @@ type prepareRequest struct {
|
||||||
transactionHashes []util.Uint256
|
transactionHashes []util.Uint256
|
||||||
minerTx transaction.Transaction
|
minerTx transaction.Transaction
|
||||||
nextConsensus util.Uint160
|
nextConsensus util.Uint160
|
||||||
|
proposalStateRoot state.MPTRootBase
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ payload.PrepareRequest = (*prepareRequest)(nil)
|
var _ payload.PrepareRequest = (*prepareRequest)(nil)
|
||||||
|
@ -25,6 +27,7 @@ func (p *prepareRequest) EncodeBinary(w *io.BinWriter) {
|
||||||
w.WriteBytes(p.nextConsensus[:])
|
w.WriteBytes(p.nextConsensus[:])
|
||||||
w.WriteArray(p.transactionHashes)
|
w.WriteArray(p.transactionHashes)
|
||||||
p.minerTx.EncodeBinary(w)
|
p.minerTx.EncodeBinary(w)
|
||||||
|
p.proposalStateRoot.EncodeBinary(w)
|
||||||
}
|
}
|
||||||
|
|
||||||
// DecodeBinary implements io.Serializable interface.
|
// DecodeBinary implements io.Serializable interface.
|
||||||
|
@ -34,6 +37,7 @@ func (p *prepareRequest) DecodeBinary(r *io.BinReader) {
|
||||||
r.ReadBytes(p.nextConsensus[:])
|
r.ReadBytes(p.nextConsensus[:])
|
||||||
r.ReadArray(&p.transactionHashes)
|
r.ReadArray(&p.transactionHashes)
|
||||||
p.minerTx.DecodeBinary(r)
|
p.minerTx.DecodeBinary(r)
|
||||||
|
p.proposalStateRoot.DecodeBinary(r)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Timestamp implements payload.PrepareRequest interface.
|
// Timestamp implements payload.PrepareRequest interface.
|
||||||
|
|
Loading…
Reference in a new issue