consensus: return signed messages from recovery.Get*

This commit is contained in:
Evgenii Stratonikov 2019-12-02 18:32:14 +03:00
parent 652ede03c8
commit 765c354793
4 changed files with 103 additions and 20 deletions

2
go.mod
View file

@ -10,7 +10,7 @@ require (
github.com/mattn/go-colorable v0.1.4 // indirect
github.com/mattn/go-isatty v0.0.10 // indirect
github.com/mr-tron/base58 v1.1.2
github.com/nspcc-dev/dbft v0.0.0-20191125155719-1c35ab053055
github.com/nspcc-dev/dbft v0.0.0-20191205084618-dacb1a30c254
github.com/nspcc-dev/rfc6979 v0.1.0
github.com/onsi/ginkgo v1.10.3 // indirect
github.com/onsi/gomega v1.7.1 // indirect

4
go.sum
View file

@ -88,8 +88,8 @@ github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3Rllmb
github.com/mr-tron/base58 v1.1.2 h1:ZEw4I2EgPKDJ2iEw0cNmLB3ROrEmkOtXIkaG7wZg+78=
github.com/mr-tron/base58 v1.1.2/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc=
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
github.com/nspcc-dev/dbft v0.0.0-20191125155719-1c35ab053055 h1:Rs8zeSFfXOX2RuUjWwsUrQpNbxoWyeXU8lWPlYkxDo0=
github.com/nspcc-dev/dbft v0.0.0-20191125155719-1c35ab053055/go.mod h1:w1Ln2aT+dBlPhLnuZhBV+DfPEdS2CHWWLp5JTScY3bw=
github.com/nspcc-dev/dbft v0.0.0-20191205084618-dacb1a30c254 h1:A4OkQDQOSPsJF8qUmqNvFDzmIGALrvOCZrMktllDoKc=
github.com/nspcc-dev/dbft v0.0.0-20191205084618-dacb1a30c254/go.mod h1:w1Ln2aT+dBlPhLnuZhBV+DfPEdS2CHWWLp5JTScY3bw=
github.com/nspcc-dev/neofs-crypto v0.2.0 h1:ftN+59WqxSWz/RCgXYOfhmltOOqU+udsNQSvN6wkFck=
github.com/nspcc-dev/neofs-crypto v0.2.0/go.mod h1:F/96fUzPM3wR+UGsPi3faVNmFlA9KAEAUQR7dMxZmNA=
github.com/nspcc-dev/rfc6979 v0.1.0 h1:Lwg7esRRoyK1Up/IN1vAef1EmvrBeMHeeEkek2fAJ6c=

View file

@ -3,6 +3,7 @@ package consensus
import (
"github.com/CityOfZion/neo-go/pkg/io"
"github.com/CityOfZion/neo-go/pkg/util"
"github.com/nspcc-dev/dbft/crypto"
"github.com/nspcc-dev/dbft/payload"
"github.com/pkg/errors"
)
@ -138,6 +139,10 @@ func (m *recoveryMessage) AddPayload(p payload.ConsensusPayload) {
m.prepareRequest = p.GetPrepareRequest().(*prepareRequest)
h := p.Hash()
m.preparationHash = &h
m.preparationPayloads = append(m.preparationPayloads, &preparationCompact{
ValidatorIndex: p.ValidatorIndex(),
InvocationScript: p.(*Payload).Witness.InvocationScript,
})
case payload.PrepareResponseType:
m.preparationPayloads = append(m.preparationPayloads, &preparationCompact{
ValidatorIndex: p.ValidatorIndex(),
@ -166,16 +171,33 @@ func (m *recoveryMessage) AddPayload(p payload.ConsensusPayload) {
}
// GetPrepareRequest implements payload.RecoveryMessage interface.
func (m *recoveryMessage) GetPrepareRequest(p payload.ConsensusPayload) payload.ConsensusPayload {
func (m *recoveryMessage) GetPrepareRequest(p payload.ConsensusPayload, validators []crypto.PublicKey, primary uint16) payload.ConsensusPayload {
if m.prepareRequest == nil {
return nil
}
return fromPayload(prepareRequestType, p.(*Payload), m.prepareRequest)
var compact *preparationCompact
for _, p := range m.preparationPayloads {
if p != nil && p.ValidatorIndex == primary {
compact = p
break
}
}
if compact == nil {
return nil
}
req := fromPayload(prepareRequestType, p.(*Payload), m.prepareRequest)
req.SetValidatorIndex(primary)
req.Witness.InvocationScript = compact.InvocationScript
req.Witness.VerificationScript = getVerificationScript(primary, validators)
return req
}
// GetPrepareResponses implements payload.RecoveryMessage interface.
func (m *recoveryMessage) GetPrepareResponses(p payload.ConsensusPayload) []payload.ConsensusPayload {
func (m *recoveryMessage) GetPrepareResponses(p payload.ConsensusPayload, validators []crypto.PublicKey) []payload.ConsensusPayload {
if m.preparationHash == nil {
return nil
}
@ -183,38 +205,49 @@ func (m *recoveryMessage) GetPrepareResponses(p payload.ConsensusPayload) []payl
ps := make([]payload.ConsensusPayload, len(m.preparationPayloads))
for i, resp := range m.preparationPayloads {
ps[i] = fromPayload(prepareResponseType, p.(*Payload), &prepareResponse{
r := fromPayload(prepareResponseType, p.(*Payload), &prepareResponse{
preparationHash: *m.preparationHash,
})
ps[i].SetValidatorIndex(resp.ValidatorIndex)
r.SetValidatorIndex(resp.ValidatorIndex)
r.Witness.InvocationScript = resp.InvocationScript
r.Witness.VerificationScript = getVerificationScript(resp.ValidatorIndex, validators)
ps[i] = r
}
return ps
}
// GetChangeViews implements payload.RecoveryMessage interface.
func (m *recoveryMessage) GetChangeViews(p payload.ConsensusPayload) []payload.ConsensusPayload {
func (m *recoveryMessage) GetChangeViews(p payload.ConsensusPayload, validators []crypto.PublicKey) []payload.ConsensusPayload {
ps := make([]payload.ConsensusPayload, len(m.changeViewPayloads))
for i, cv := range m.changeViewPayloads {
ps[i] = fromPayload(changeViewType, p.(*Payload), &changeView{
c := fromPayload(changeViewType, p.(*Payload), &changeView{
newViewNumber: cv.OriginalViewNumber + 1,
timestamp: cv.Timestamp,
})
ps[i].SetValidatorIndex(cv.ValidatorIndex)
c.SetValidatorIndex(cv.ValidatorIndex)
c.Witness.InvocationScript = cv.InvocationScript
c.Witness.VerificationScript = getVerificationScript(cv.ValidatorIndex, validators)
ps[i] = c
}
return ps
}
// GetCommits implements payload.RecoveryMessage interface.
func (m *recoveryMessage) GetCommits(p payload.ConsensusPayload) []payload.ConsensusPayload {
func (m *recoveryMessage) GetCommits(p payload.ConsensusPayload, validators []crypto.PublicKey) []payload.ConsensusPayload {
ps := make([]payload.ConsensusPayload, len(m.commitPayloads))
for i, c := range m.commitPayloads {
cc := commit{signature: c.Signature}
ps[i] = fromPayload(commitType, p.(*Payload), &cc)
ps[i].SetValidatorIndex(c.ValidatorIndex)
cc := fromPayload(commitType, p.(*Payload), &commit{signature: c.Signature})
cc.SetValidatorIndex(c.ValidatorIndex)
cc.Witness.InvocationScript = c.InvocationScript
cc.Witness.VerificationScript = getVerificationScript(c.ValidatorIndex, validators)
ps[i] = cc
}
return ps
@ -230,6 +263,19 @@ func (m *recoveryMessage) SetPreparationHash(h *util.Uint256) {
m.preparationHash = h
}
func getVerificationScript(i uint16, validators []crypto.PublicKey) []byte {
if int(i) >= len(validators) {
return nil
}
pub, ok := validators[i].(*publicKey)
if !ok {
return nil
}
return pub.GetVerificationScript()
}
func fromPayload(t messageType, recovery *Payload, p io.Serializable) *Payload {
return &Payload{
message: message{

View file

@ -3,16 +3,28 @@ package consensus
import (
"testing"
"github.com/CityOfZion/neo-go/pkg/crypto/keys"
"github.com/CityOfZion/neo-go/pkg/util"
"github.com/nspcc-dev/dbft/crypto"
"github.com/nspcc-dev/dbft/payload"
"github.com/stretchr/testify/require"
)
func TestRecoveryMessage_Setters(t *testing.T) {
const size = 5
privs := getKeys(t, size)
pubs := make([]crypto.PublicKey, 5)
for i := range pubs {
pubs[i] = &publicKey{privs[i].PublicKey()}
}
r := &recoveryMessage{}
p := new(Payload)
p.SetType(payload.RecoveryMessageType)
p.SetPayload(r)
// sign payload to have verification script
require.NoError(t, p.Sign(privs[0]))
req := &prepareRequest{
timestamp: 87,
@ -24,6 +36,8 @@ func TestRecoveryMessage_Setters(t *testing.T) {
p1 := new(Payload)
p1.SetType(payload.PrepareRequestType)
p1.SetPayload(req)
p1.SetValidatorIndex(0)
require.NoError(t, p1.Sign(privs[0]))
t.Run("prepare response is added", func(t *testing.T) {
p2 := new(Payload)
@ -31,24 +45,28 @@ func TestRecoveryMessage_Setters(t *testing.T) {
p2.SetPayload(&prepareResponse{
preparationHash: p1.Hash(),
})
p2.SetValidatorIndex(1)
require.NoError(t, p2.Sign(privs[1]))
r.AddPayload(p2)
require.NotNil(t, r.PreparationHash())
require.Equal(t, p1.Hash(), *r.PreparationHash())
ps := r.GetPrepareResponses(p)
ps := r.GetPrepareResponses(p, pubs)
require.Len(t, ps, 1)
require.Equal(t, p2, ps[0])
require.True(t, ps[0].(*Payload).Verify())
})
t.Run("prepare request is added", func(t *testing.T) {
pr := r.GetPrepareRequest(p)
pr := r.GetPrepareRequest(p, pubs, p1.ValidatorIndex())
require.Nil(t, pr)
r.AddPayload(p1)
pr = r.GetPrepareRequest(p)
pr = r.GetPrepareRequest(p, pubs, p1.ValidatorIndex())
require.NotNil(t, pr)
require.Equal(t, p1, pr)
require.True(t, pr.(*Payload).Verify())
})
t.Run("change view is added", func(t *testing.T) {
@ -58,23 +76,42 @@ func TestRecoveryMessage_Setters(t *testing.T) {
newViewNumber: 1,
timestamp: 12345,
})
p3.SetValidatorIndex(3)
require.NoError(t, p3.Sign(privs[3]))
r.AddPayload(p3)
ps := r.GetChangeViews(p)
ps := r.GetChangeViews(p, pubs)
require.Len(t, ps, 1)
require.Equal(t, p3, ps[0])
require.True(t, ps[0].(*Payload).Verify())
})
t.Run("commit is added", func(t *testing.T) {
p4 := new(Payload)
p4.SetType(payload.CommitType)
p4.SetPayload(randomMessage(t, commitType))
p4.SetValidatorIndex(4)
require.NoError(t, p4.Sign(privs[4]))
r.AddPayload(p4)
ps := r.GetCommits(p)
ps := r.GetCommits(p, pubs)
require.Len(t, ps, 1)
require.Equal(t, p4, ps[0])
require.True(t, ps[0].(*Payload).Verify())
})
}
func getKeys(t *testing.T, n int) []*privateKey {
privs := make([]*privateKey, 0, n)
for i := 0; i < n; i++ {
priv, err := keys.NewPrivateKey()
require.NoError(t, err)
require.NotNil(t, priv)
privs = append(privs, &privateKey{PrivateKey: priv})
}
return privs
}