privval: Switch to amino encoding in SignBytes (#2459)

* switch to amino for SignBytes and add Reply with error message

- currently only Vote is done

* switch Reply type in socket for other messages

 - add error description on error

* add TODOs regarding error handling

* address comments from peer review session (thx @xla)

 - contains all changes besides the test-coverage / error'ing branches

* increase test coverage:

 - add tests for each newly introduced error'ing code path

* return error if received wrong response

* add test for wrong response branches (ErrUnexpectedResponse)

* update CHANGELOG_PENDING and related documentation (spec)

* fix typo: s/CanonicallockID/CanonicalBlockID

* fixes from review
This commit is contained in:
Ismail Khoffi
2018-09-28 19:57:29 -04:00
committed by Ethan Buchman
parent 47bc15c27a
commit fc073746a0
15 changed files with 490 additions and 217 deletions
+12 -4
View File
@@ -401,14 +401,22 @@ must be greater than 2/3 of the total voting power of the complete validator set
A vote is a signed message broadcast in the consensus for a particular block at a particular height and round.
When stored in the blockchain or propagated over the network, votes are encoded in Amino.
For signing, votes are encoded in JSON, and the ChainID is included, in the form of the `CanonicalSignBytes`.
For signing, votes are represented via `CanonicalVote` and also encoded using amino (protobuf compatible) via
`Vote.SignBytes` which includes the `ChainID`.
We define a method `Verify` that returns `true` if the signature verifies against the pubkey for the CanonicalSignBytes
We define a method `Verify` that returns `true` if the signature verifies against the pubkey for the `SignBytes`
using the given ChainID:
```go
func (v Vote) Verify(chainID string, pubKey PubKey) bool {
return pubKey.Verify(v.Signature, CanonicalSignBytes(chainID, v))
func (vote *Vote) Verify(chainID string, pubKey crypto.PubKey) error {
if !bytes.Equal(pubKey.Address(), vote.ValidatorAddress) {
return ErrVoteInvalidValidatorAddress
}
if !pubKey.VerifyBytes(vote.SignBytes(chainID), vote.Signature) {
return ErrVoteInvalidSignature
}
return nil
}
```
+16 -8
View File
@@ -298,14 +298,22 @@ Where the `"value"` is the base64 encoding of the raw pubkey bytes, and the
### Signed Messages
Signed messages (eg. votes, proposals) in the consensus are encoded using Amino-JSON, rather than in the standard binary format
(NOTE: this is subject to change: https://github.com/tendermint/tendermint/issues/1622)
Signed messages (eg. votes, proposals) in the consensus are encoded using Amino.
When signing, the elements of a message are sorted by key and prepended with
a `@chain_id` and `@type` field.
We call this encoding the CanonicalSignBytes. For instance, CanonicalSignBytes for a vote would look
like:
When signing, the elements of a message are sorted alphabetically by key and prepended with
a `chain_id` and `type` field.
We call this encoding the SignBytes. For instance, SignBytes for a vote is the Amino encoding of the following struct:
```json
{"@chain_id":"test_chain_id","@type":"vote","block_id":{"hash":"8B01023386C371778ECB6368573E539AFC3CC860","parts":{"hash":"72DB3D959635DFF1BB567BEDAA70573392C51596","total":"1000000"}},"height":"12345","round":"2","timestamp":"2017-12-25T03:00:01.234Z","type":2}
```go
type CanonicalVote struct {
ChainID string
Type string
BlockID CanonicalBlockID
Height int64
Round int
Timestamp time.Time
VoteType byte
}
```
NOTE: see [#1622](https://github.com/tendermint/tendermint/issues/1622) for how field ordering will change