From c5c2b9601f02747d50e70f54a71f40270a659956 Mon Sep 17 00:00:00 2001 From: Ethan Buchman Date: Sun, 5 Aug 2018 14:14:56 -0400 Subject: [PATCH 1/5] update changelog and version --- CHANGELOG.md | 39 +++++++++++++++++++++++++++++++++++++++ CHANGELOG_PENDING.md | 30 ------------------------------ Makefile | 2 +- version/version.go | 6 +++--- 4 files changed, 43 insertions(+), 34 deletions(-) delete mode 100644 CHANGELOG_PENDING.md diff --git a/CHANGELOG.md b/CHANGELOG.md index b2bda54c..957e749a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,44 @@ # Changelog +## 0.23.0 + +*August 5th, 2018* + +This release includes a breaking upgrade to the p2p encryption and some minor +breaking changes in the ABCI. A few more changes are still coming to the Header, ABCI, +and validator set handling to better support light clients, BFT time, and +upgrades. Most notably, validator set changes will be delayed by one block (see +[#1815]). + +BREAKING CHANGES: +- [abci] Changed time format from int64 to google.protobuf.Timestamp +- [abci] Changed Validators to LastCommitInfo in RequestBeginBlock +- [abci] Removed Fee from ResponseDeliverTx and ResponseCheckTx +- [p2p] Remove salsa and ripemd primitives, in favor of using chacha as a stream cipher, and hkdf +- [tools] Removed `make ensure_deps` in favor of `make get_vendor_deps` +- [types] CanonicalTime uses nanoseconds instead of clipping to ms + - breaks serialization/signing of all messages with a timestamp + +FEATURES: +- [tools] Added `make check_dep` + - ensures gopkg.lock is synced with gopkg.toml + - ensures no branches are used in the gopkg.toml + +IMPROVEMENTS: +- [blockchain] Improve fast-sync logic + - tweak params + - only process one block at a time to avoid starving +- [common] bit array functions which take in another parameter are now thread safe +- [crypto] Switch hkdfchachapoly1305 to xchachapoly1305 +- [p2p] begin connecting to peers as soon a seed node provides them to you ([#2093](https://github.com/tendermint/tendermint/issues/2093)) + +BUG FIXES: +- [common] Safely handle cases where atomic write files already exist [#2109](https://github.com/tendermint/tendermint/issues/2109) +- [privval] fix a deadline for accepting new connections in socket private + validator. +- [p2p] Allow startup if a configured seed node's IP can't be resolved ([#1716](https://github.com/tendermint/tendermint/issues/1716)) +- [node] Fully exit when CTRL-C is pressed even if consensus state panics [#2072](https://github.com/tendermint/tendermint/issues/2072) + ## 0.22.8 *July 26th, 2018* diff --git a/CHANGELOG_PENDING.md b/CHANGELOG_PENDING.md deleted file mode 100644 index a1d9985a..00000000 --- a/CHANGELOG_PENDING.md +++ /dev/null @@ -1,30 +0,0 @@ -# Pending - -BREAKING CHANGES: -- [types] CanonicalTime uses nanoseconds instead of clipping to ms - - breaks serialization/signing of all messages with a timestamp -- [abci] Removed Fee from ResponseDeliverTx and ResponseCheckTx -- [tools] Removed `make ensure_deps` in favor of `make get_vendor_deps` -- [p2p] Remove salsa and ripemd primitives, in favor of using chacha as a stream cipher, and hkdf -- [abci] Changed time format from int64 to google.protobuf.Timestamp -- [abci] Changed Validators to LastCommitInfo in RequestBeginBlock - -FEATURES: -- [tools] Added `make check_dep` - - ensures gopkg.lock is synced with gopkg.toml - - ensures no branches are used in the gopkg.toml - -IMPROVEMENTS: -- [blockchain] Improve fast-sync logic - - tweak params - - only process one block at a time to avoid starving -- [crypto] Switch hkdfchachapoly1305 to xchachapoly1305 -- [common] bit array functions which take in another parameter are now thread safe -- [p2p] begin connecting to peers as soon a seed node provides them to you ([#2093](https://github.com/tendermint/tendermint/issues/2093)) - -BUG FIXES: -- [common] Safely handle cases where atomic write files already exist [#2109](https://github.com/tendermint/tendermint/issues/2109) -- [privval] fix a deadline for accepting new connections in socket private - validator. -- [p2p] Allow startup if a configured seed node's IP can't be resolved ([#1716](https://github.com/tendermint/tendermint/issues/1716)) -- [node] Fully exit when CTRL-C is pressed even if consensus state panics [#2072](https://github.com/tendermint/tendermint/issues/2072) diff --git a/Makefile b/Makefile index 45703c84..22e92886 100644 --- a/Makefile +++ b/Makefile @@ -13,7 +13,7 @@ BUILD_FLAGS = -ldflags "-X github.com/tendermint/tendermint/version.GitCommit=`g all: check build test install -check: check_tools ensure_deps +check: check_tools get_vendor_deps ######################################## diff --git a/version/version.go b/version/version.go index 85b1f191..04880cfe 100644 --- a/version/version.go +++ b/version/version.go @@ -3,14 +3,14 @@ package version // Version components const ( Maj = "0" - Min = "22" - Fix = "8" + Min = "23" + Fix = "0" ) var ( // Version is the current version of Tendermint // Must be a string because scripts like dist.sh read this file. - Version = "0.22.8" + Version = "0.23.0" // GitCommit is the current HEAD set using ldflags. GitCommit string From d6a666b445f34ebabdd3d6b0d1202a6dd47bdbfa Mon Sep 17 00:00:00 2001 From: Dev Ojha Date: Sun, 5 Aug 2018 11:47:01 -0700 Subject: [PATCH 2/5] p2p/pex: Fix mismatch between dialseeds and checkseeds. (#2151) --- p2p/pex/pex_reactor.go | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/p2p/pex/pex_reactor.go b/p2p/pex/pex_reactor.go index 4220dd42..288cb0d1 100644 --- a/p2p/pex/pex_reactor.go +++ b/p2p/pex/pex_reactor.go @@ -504,12 +504,7 @@ func (r *PEXReactor) checkSeeds() (numOnline int, netAddrs []*p2p.NetAddress, er // randomly dial seeds until we connect to one or exhaust them func (r *PEXReactor) dialSeeds() { - lSeeds := len(r.config.Seeds) - if lSeeds == 0 { - return - } - - perm := cmn.RandPerm(lSeeds) + perm := cmn.RandPerm(len(r.seedAddrs)) // perm := r.Switch.rng.Perm(lSeeds) for _, i := range perm { // dial a random seed From f903947ff3e09a959d96ec7e76c249672f7cf15c Mon Sep 17 00:00:00 2001 From: ValarDragon Date: Wed, 1 Aug 2018 17:02:05 -0700 Subject: [PATCH 3/5] crypto: Remove interface from crypto.Signature Signatures are now []byte, which saves on the number of bytes after amino encoding (squash this) address Ismail's comment --- abci/example/example_test.go | 4 +- consensus/types/round_state_test.go | 2 +- crypto/README.md | 2 - crypto/crypto.go | 10 +---- crypto/ed25519/ed25519.go | 64 ++++++---------------------- crypto/ed25519/ed25519_test.go | 4 +- crypto/encoding/amino/amino.go | 11 ----- crypto/encoding/amino/encode_test.go | 16 +++---- crypto/secp256k1/secp256k1.go | 57 +++---------------------- crypto/secp256k1/secpk256k1_test.go | 4 +- node/id.go | 2 +- p2p/conn/secret_connection.go | 6 +-- privval/priv_validator.go | 20 ++++----- privval/priv_validator_test.go | 5 +-- types/heartbeat.go | 16 +++---- types/heartbeat_test.go | 4 +- types/proposal.go | 16 +++---- types/proposal_test.go | 2 +- types/protobuf_test.go | 2 +- types/vote.go | 2 +- types/vote_set.go | 2 +- 21 files changed, 69 insertions(+), 182 deletions(-) diff --git a/abci/example/example_test.go b/abci/example/example_test.go index 7e8bd2e5..8fa3ae02 100644 --- a/abci/example/example_test.go +++ b/abci/example/example_test.go @@ -7,6 +7,8 @@ import ( "testing" "time" + "github.com/stretchr/testify/require" + "google.golang.org/grpc" "golang.org/x/net/context" @@ -43,7 +45,7 @@ func testStream(t *testing.T, app types.Application) { server := abciserver.NewSocketServer("unix://test.sock", app) server.SetLogger(log.TestingLogger().With("module", "abci-server")) if err := server.Start(); err != nil { - t.Fatalf("Error starting socket server: %v", err.Error()) + require.NoError(t, err, "Error starting socket server") } defer server.Stop() diff --git a/consensus/types/round_state_test.go b/consensus/types/round_state_test.go index bcaa6308..0257ea2f 100644 --- a/consensus/types/round_state_test.go +++ b/consensus/types/round_state_test.go @@ -23,7 +23,7 @@ func BenchmarkRoundStateDeepCopy(b *testing.B) { Hash: cmn.RandBytes(20), }, } - sig := ed25519.SignatureEd25519{} + sig := make([]byte, ed25519.SignatureEd25519Size) for i := 0; i < nval; i++ { precommits[i] = &types.Vote{ ValidatorAddress: types.Address(cmn.RandBytes(20)), diff --git a/crypto/README.md b/crypto/README.md index 5fac6733..bb663122 100644 --- a/crypto/README.md +++ b/crypto/README.md @@ -24,9 +24,7 @@ crypto `.Bytes()` uses Amino:binary encoding, but Amino:JSON is also supported. Example Amino:JSON encodings: ed25519.PrivKeyEd25519 - {"type":"954568A3288910","value":"EVkqJO/jIXp3rkASXfh9YnyToYXRXhBr6g9cQVxPFnQBP/5povV4HTjvsy530kybxKHwEi85iU8YL0qQhSYVoQ=="} -crypto.SignatureEd25519 - {"type":"6BF5903DA1DB28","value":"77sQNZOrf7ltExpf7AV1WaYPCHbyRLgjBsoWVzcduuLk+jIGmYk+s5R6Emm29p12HeiNAuhUJgdFGmwkpeGJCA=="} ed25519.PubKeyEd25519 - {"type":"AC26791624DE60","value":"AT/+aaL1eB0477Mud9JMm8Sh8BIvOYlPGC9KkIUmFaE="} crypto.PrivKeySecp256k1 - {"type":"019E82E1B0F798","value":"zx4Pnh67N+g2V+5vZbQzEyRerX9c4ccNZOVzM9RvJ0Y="} -crypto.SignatureSecp256k1 - {"type":"6D1EA416E1FEE8","value":"MEUCIQCIg5TqS1l7I+MKTrSPIuUN2+4m5tA29dcauqn3NhEJ2wIgICaZ+lgRc5aOTVahU/XoLopXKn8BZcl0bnuYWLvohR8="} crypto.PubKeySecp256k1 - {"type":"F8CCEAEB5AE980","value":"A8lPKJXcNl5VHt1FK8a244K9EJuS4WX1hFBnwisi0IJx"} ``` diff --git a/crypto/crypto.go b/crypto/crypto.go index 4c097b35..09c12ff7 100644 --- a/crypto/crypto.go +++ b/crypto/crypto.go @@ -6,7 +6,7 @@ import ( type PrivKey interface { Bytes() []byte - Sign(msg []byte) (Signature, error) + Sign(msg []byte) ([]byte, error) PubKey() PubKey Equals(PrivKey) bool } @@ -19,16 +19,10 @@ type Address = cmn.HexBytes type PubKey interface { Address() Address Bytes() []byte - VerifyBytes(msg []byte, sig Signature) bool + VerifyBytes(msg []byte, sig []byte) bool Equals(PubKey) bool } -type Signature interface { - Bytes() []byte - IsZero() bool - Equals(Signature) bool -} - type Symmetric interface { Keygen() []byte Encrypt(plaintext []byte, secret []byte) (ciphertext []byte) diff --git a/crypto/ed25519/ed25519.go b/crypto/ed25519/ed25519.go index 3dd4d2b3..fa7526f3 100644 --- a/crypto/ed25519/ed25519.go +++ b/crypto/ed25519/ed25519.go @@ -11,7 +11,6 @@ import ( amino "github.com/tendermint/go-amino" "github.com/tendermint/tendermint/crypto" "github.com/tendermint/tendermint/crypto/tmhash" - cmn "github.com/tendermint/tendermint/libs/common" ) //------------------------------------- @@ -19,9 +18,11 @@ import ( var _ crypto.PrivKey = PrivKeyEd25519{} const ( - Ed25519PrivKeyAminoRoute = "tendermint/PrivKeyEd25519" - Ed25519PubKeyAminoRoute = "tendermint/PubKeyEd25519" - Ed25519SignatureAminoRoute = "tendermint/SignatureEd25519" + Ed25519PrivKeyAminoRoute = "tendermint/PrivKeyEd25519" + Ed25519PubKeyAminoRoute = "tendermint/PubKeyEd25519" + // Size of an Edwards25519 signature. Namely the size of a compressed + // Edwards25519 point, and a field element. Both of which are 32 bytes. + SignatureEd25519Size = 64 ) var cdc = amino.NewCodec() @@ -34,10 +35,6 @@ func init() { cdc.RegisterInterface((*crypto.PrivKey)(nil), nil) cdc.RegisterConcrete(PrivKeyEd25519{}, Ed25519PrivKeyAminoRoute, nil) - - cdc.RegisterInterface((*crypto.Signature)(nil), nil) - cdc.RegisterConcrete(SignatureEd25519{}, - Ed25519SignatureAminoRoute, nil) } // PrivKeyEd25519 implements crypto.PrivKey. @@ -49,10 +46,10 @@ func (privKey PrivKeyEd25519) Bytes() []byte { } // Sign produces a signature on the provided message. -func (privKey PrivKeyEd25519) Sign(msg []byte) (crypto.Signature, error) { +func (privKey PrivKeyEd25519) Sign(msg []byte) ([]byte, error) { privKeyBytes := [64]byte(privKey) signatureBytes := ed25519.Sign(&privKeyBytes, msg) - return SignatureEd25519(*signatureBytes), nil + return signatureBytes[:], nil } // PubKey gets the corresponding public key from the private key. @@ -159,15 +156,15 @@ func (pubKey PubKeyEd25519) Bytes() []byte { return bz } -func (pubKey PubKeyEd25519) VerifyBytes(msg []byte, sig_ crypto.Signature) bool { +func (pubKey PubKeyEd25519) VerifyBytes(msg []byte, sig_ []byte) bool { // make sure we use the same algorithm to sign - sig, ok := sig_.(SignatureEd25519) - if !ok { + if len(sig_) != SignatureEd25519Size { return false } + sig := new([SignatureEd25519Size]byte) + copy(sig[:], sig_) pubKeyBytes := [PubKeyEd25519Size]byte(pubKey) - sigBytes := [SignatureEd25519Size]byte(sig) - return ed25519.Verify(&pubKeyBytes, msg, &sigBytes) + return ed25519.Verify(&pubKeyBytes, msg, sig) } // ToCurve25519 takes a public key and returns its representation on @@ -197,40 +194,3 @@ func (pubKey PubKeyEd25519) Equals(other crypto.PubKey) bool { return false } } - -//------------------------------------- - -var _ crypto.Signature = SignatureEd25519{} - -// Size of an Edwards25519 signature. Namely the size of a compressed -// Edwards25519 point, and a field element. Both of which are 32 bytes. -const SignatureEd25519Size = 64 - -// SignatureEd25519 implements crypto.Signature -type SignatureEd25519 [SignatureEd25519Size]byte - -func (sig SignatureEd25519) Bytes() []byte { - bz, err := cdc.MarshalBinaryBare(sig) - if err != nil { - panic(err) - } - return bz -} - -func (sig SignatureEd25519) IsZero() bool { return len(sig) == 0 } - -func (sig SignatureEd25519) String() string { return fmt.Sprintf("/%X.../", cmn.Fingerprint(sig[:])) } - -func (sig SignatureEd25519) Equals(other crypto.Signature) bool { - if otherEd, ok := other.(SignatureEd25519); ok { - return subtle.ConstantTimeCompare(sig[:], otherEd[:]) == 1 - } else { - return false - } -} - -func SignatureEd25519FromBytes(data []byte) crypto.Signature { - var sig SignatureEd25519 - copy(sig[:], data) - return sig -} diff --git a/crypto/ed25519/ed25519_test.go b/crypto/ed25519/ed25519_test.go index 5c407ccd..50305027 100644 --- a/crypto/ed25519/ed25519_test.go +++ b/crypto/ed25519/ed25519_test.go @@ -23,9 +23,7 @@ func TestSignAndValidateEd25519(t *testing.T) { // Mutate the signature, just one bit. // TODO: Replace this with a much better fuzzer, tendermint/ed25519/issues/10 - sigEd := sig.(ed25519.SignatureEd25519) - sigEd[7] ^= byte(0x01) - sig = sigEd + sig[7] ^= byte(0x01) assert.False(t, pubKey.VerifyBytes(msg, sig)) } diff --git a/crypto/encoding/amino/amino.go b/crypto/encoding/amino/amino.go index 2b5e15b4..fd9a0844 100644 --- a/crypto/encoding/amino/amino.go +++ b/crypto/encoding/amino/amino.go @@ -33,12 +33,6 @@ func RegisterAmino(cdc *amino.Codec) { "tendermint/PrivKeyEd25519", nil) cdc.RegisterConcrete(secp256k1.PrivKeySecp256k1{}, "tendermint/PrivKeySecp256k1", nil) - - cdc.RegisterInterface((*crypto.Signature)(nil), nil) - cdc.RegisterConcrete(ed25519.SignatureEd25519{}, - "tendermint/SignatureEd25519", nil) - cdc.RegisterConcrete(secp256k1.SignatureSecp256k1{}, - "tendermint/SignatureSecp256k1", nil) } func PrivKeyFromBytes(privKeyBytes []byte) (privKey crypto.PrivKey, err error) { @@ -50,8 +44,3 @@ func PubKeyFromBytes(pubKeyBytes []byte) (pubKey crypto.PubKey, err error) { err = cdc.UnmarshalBinaryBare(pubKeyBytes, &pubKey) return } - -func SignatureFromBytes(pubKeyBytes []byte) (pubKey crypto.Signature, err error) { - err = cdc.UnmarshalBinaryBare(pubKeyBytes, &pubKey) - return -} diff --git a/crypto/encoding/amino/encode_test.go b/crypto/encoding/amino/encode_test.go index e0120608..0581ba64 100644 --- a/crypto/encoding/amino/encode_test.go +++ b/crypto/encoding/amino/encode_test.go @@ -15,12 +15,14 @@ type byter interface { Bytes() []byte } -func checkAminoBinary(t *testing.T, src byter, dst interface{}, size int) { +func checkAminoBinary(t *testing.T, src, dst interface{}, size int) { // Marshal to binary bytes. bz, err := cdc.MarshalBinaryBare(src) require.Nil(t, err, "%+v", err) - // Make sure this is compatible with current (Bytes()) encoding. - assert.Equal(t, src.Bytes(), bz, "Amino binary vs Bytes() mismatch") + if byterSrc, ok := src.(byter); ok { + // Make sure this is compatible with current (Bytes()) encoding. + assert.Equal(t, byterSrc.Bytes(), bz, "Amino binary vs Bytes() mismatch") + } // Make sure we have the expected length. if size != -1 { assert.Equal(t, size, len(bz), "Amino binary size mismatch") @@ -53,8 +55,6 @@ func ExamplePrintRegisteredTypes() { //| PubKeySecp256k1 | tendermint/PubKeySecp256k1 | 0xEB5AE987 | 0x21 | | //| PrivKeyEd25519 | tendermint/PrivKeyEd25519 | 0xA3288910 | 0x40 | | //| PrivKeySecp256k1 | tendermint/PrivKeySecp256k1 | 0xE1B0F79B | 0x20 | | - //| SignatureEd25519 | tendermint/SignatureEd25519 | 0x2031EA53 | 0x40 | | - //| SignatureSecp256k1 | tendermint/SignatureSecp256k1 | 0x7FC4A495 | variable | | } func TestKeyEncodings(t *testing.T) { @@ -84,13 +84,11 @@ func TestKeyEncodings(t *testing.T) { assert.EqualValues(t, tc.privKey, priv3, "tc #%d", tcIndex) // Check (de/en)codings of Signatures. - var sig1, sig2, sig3 crypto.Signature + var sig1, sig2 []byte sig1, err := tc.privKey.Sign([]byte("something")) assert.NoError(t, err, "tc #%d", tcIndex) checkAminoBinary(t, sig1, &sig2, -1) // Signature size changes for Secp anyways. assert.EqualValues(t, sig1, sig2, "tc #%d", tcIndex) - checkAminoJSON(t, sig1, &sig3, false) // TODO also check Prefix bytes. - assert.EqualValues(t, sig1, sig3, "tc #%d", tcIndex) // Check (de/en)codings of PubKeys. pubKey := tc.privKey.PubKey() @@ -105,7 +103,7 @@ func TestKeyEncodings(t *testing.T) { func TestNilEncodings(t *testing.T) { // Check nil Signature. - var a, b crypto.Signature + var a, b []byte checkAminoJSON(t, &a, &b, true) assert.EqualValues(t, a, b) diff --git a/crypto/secp256k1/secp256k1.go b/crypto/secp256k1/secp256k1.go index 03d5614a..aee5dafe 100644 --- a/crypto/secp256k1/secp256k1.go +++ b/crypto/secp256k1/secp256k1.go @@ -10,15 +10,13 @@ import ( secp256k1 "github.com/btcsuite/btcd/btcec" amino "github.com/tendermint/go-amino" "github.com/tendermint/tendermint/crypto" - "github.com/tendermint/tendermint/libs/common" "golang.org/x/crypto/ripemd160" ) //------------------------------------- const ( - Secp256k1PrivKeyAminoRoute = "tendermint/PrivKeySecp256k1" - Secp256k1PubKeyAminoRoute = "tendermint/PubKeySecp256k1" - Secp256k1SignatureAminoRoute = "tendermint/SignatureSecp256k1" + Secp256k1PrivKeyAminoRoute = "tendermint/PrivKeySecp256k1" + Secp256k1PubKeyAminoRoute = "tendermint/PubKeySecp256k1" ) var cdc = amino.NewCodec() @@ -31,10 +29,6 @@ func init() { cdc.RegisterInterface((*crypto.PrivKey)(nil), nil) cdc.RegisterConcrete(PrivKeySecp256k1{}, Secp256k1PrivKeyAminoRoute, nil) - - cdc.RegisterInterface((*crypto.Signature)(nil), nil) - cdc.RegisterConcrete(SignatureSecp256k1{}, - Secp256k1SignatureAminoRoute, nil) } //------------------------------------- @@ -50,13 +44,13 @@ func (privKey PrivKeySecp256k1) Bytes() []byte { } // Sign creates an ECDSA signature on curve Secp256k1, using SHA256 on the msg. -func (privKey PrivKeySecp256k1) Sign(msg []byte) (crypto.Signature, error) { +func (privKey PrivKeySecp256k1) Sign(msg []byte) ([]byte, error) { priv, _ := secp256k1.PrivKeyFromBytes(secp256k1.S256(), privKey[:]) sig, err := priv.Sign(crypto.Sha256(msg)) if err != nil { return nil, err } - return SignatureSecp256k1(sig.Serialize()), nil + return sig.Serialize(), nil } // PubKey performs the point-scalar multiplication from the privKey on the @@ -142,13 +136,7 @@ func (pubKey PubKeySecp256k1) Bytes() []byte { return bz } -func (pubKey PubKeySecp256k1) VerifyBytes(msg []byte, interfaceSig crypto.Signature) bool { - // and assert same algorithm to sign and verify - sig, ok := interfaceSig.(SignatureSecp256k1) - if !ok { - return false - } - +func (pubKey PubKeySecp256k1) VerifyBytes(msg []byte, sig []byte) bool { pub, err := secp256k1.ParsePubKey(pubKey[:], secp256k1.S256()) if err != nil { return false @@ -170,38 +158,3 @@ func (pubKey PubKeySecp256k1) Equals(other crypto.PubKey) bool { } return false } - -//------------------------------------- - -var _ crypto.Signature = SignatureSecp256k1{} - -// SignatureSecp256k1 implements crypto.Signature -type SignatureSecp256k1 []byte - -func (sig SignatureSecp256k1) Bytes() []byte { - bz, err := cdc.MarshalBinaryBare(sig) - if err != nil { - panic(err) - } - return bz -} - -func (sig SignatureSecp256k1) IsZero() bool { return len(sig) == 0 } - -func (sig SignatureSecp256k1) String() string { - return fmt.Sprintf("/%X.../", common.Fingerprint(sig[:])) -} - -func (sig SignatureSecp256k1) Equals(other crypto.Signature) bool { - if otherSecp, ok := other.(SignatureSecp256k1); ok { - return subtle.ConstantTimeCompare(sig[:], otherSecp[:]) == 1 - } else { - return false - } -} - -func SignatureSecp256k1FromBytes(data []byte) crypto.Signature { - sig := make(SignatureSecp256k1, len(data)) - copy(sig[:], data) - return sig -} diff --git a/crypto/secp256k1/secpk256k1_test.go b/crypto/secp256k1/secpk256k1_test.go index 46a27b3e..0f0b5adc 100644 --- a/crypto/secp256k1/secpk256k1_test.go +++ b/crypto/secp256k1/secpk256k1_test.go @@ -59,9 +59,7 @@ func TestSignAndValidateSecp256k1(t *testing.T) { assert.True(t, pubKey.VerifyBytes(msg, sig)) // Mutate the signature, just one bit. - sigEd := sig.(secp256k1.SignatureSecp256k1) - sigEd[3] ^= byte(0x01) - sig = sigEd + sig[3] ^= byte(0x01) assert.False(t, pubKey.VerifyBytes(msg, sig)) } diff --git a/node/id.go b/node/id.go index 5100597c..d8e41eca 100644 --- a/node/id.go +++ b/node/id.go @@ -26,7 +26,7 @@ type NodeGreeting struct { type SignedNodeGreeting struct { NodeGreeting - Signature crypto.Signature + Signature []byte } func (pnid *PrivNodeID) SignGreeting() *SignedNodeGreeting { diff --git a/p2p/conn/secret_connection.go b/p2p/conn/secret_connection.go index 1b2b1da5..75199ee6 100644 --- a/p2p/conn/secret_connection.go +++ b/p2p/conn/secret_connection.go @@ -285,7 +285,7 @@ func sort32(foo, bar *[32]byte) (lo, hi *[32]byte) { return } -func signChallenge(challenge *[32]byte, locPrivKey crypto.PrivKey) (signature crypto.Signature) { +func signChallenge(challenge *[32]byte, locPrivKey crypto.PrivKey) (signature []byte) { signature, err := locPrivKey.Sign(challenge[:]) // TODO(ismail): let signChallenge return an error instead if err != nil { @@ -296,10 +296,10 @@ func signChallenge(challenge *[32]byte, locPrivKey crypto.PrivKey) (signature cr type authSigMessage struct { Key crypto.PubKey - Sig crypto.Signature + Sig []byte } -func shareAuthSignature(sc *SecretConnection, pubKey crypto.PubKey, signature crypto.Signature) (recvMsg authSigMessage, err error) { +func shareAuthSignature(sc *SecretConnection, pubKey crypto.PubKey, signature []byte) (recvMsg authSigMessage, err error) { // Send our info and receive theirs in tandem. var trs, _ = cmn.Parallel( diff --git a/privval/priv_validator.go b/privval/priv_validator.go index 5b056d8a..a81751a9 100644 --- a/privval/priv_validator.go +++ b/privval/priv_validator.go @@ -38,14 +38,14 @@ func voteToStep(vote *types.Vote) int8 { // to prevent double signing. // NOTE: the directory containing the pv.filePath must already exist. type FilePV struct { - Address types.Address `json:"address"` - PubKey crypto.PubKey `json:"pub_key"` - LastHeight int64 `json:"last_height"` - LastRound int `json:"last_round"` - LastStep int8 `json:"last_step"` - LastSignature crypto.Signature `json:"last_signature,omitempty"` // so we dont lose signatures XXX Why would we lose signatures? - LastSignBytes cmn.HexBytes `json:"last_signbytes,omitempty"` // so we dont lose signatures XXX Why would we lose signatures? - PrivKey crypto.PrivKey `json:"priv_key"` + Address types.Address `json:"address"` + PubKey crypto.PubKey `json:"pub_key"` + LastHeight int64 `json:"last_height"` + LastRound int `json:"last_round"` + LastStep int8 `json:"last_step"` + LastSignature []byte `json:"last_signature,omitempty"` // so we dont lose signatures XXX Why would we lose signatures? + LastSignBytes cmn.HexBytes `json:"last_signbytes,omitempty"` // so we dont lose signatures XXX Why would we lose signatures? + PrivKey crypto.PrivKey `json:"priv_key"` // For persistence. // Overloaded for testing. @@ -138,7 +138,7 @@ func (pv *FilePV) save() { // Reset resets all fields in the FilePV. // NOTE: Unsafe! func (pv *FilePV) Reset() { - var sig crypto.Signature + var sig []byte pv.LastHeight = 0 pv.LastRound = 0 pv.LastStep = 0 @@ -277,7 +277,7 @@ func (pv *FilePV) signProposal(chainID string, proposal *types.Proposal) error { // Persist height/round/step and signature func (pv *FilePV) saveSigned(height int64, round int, step int8, - signBytes []byte, sig crypto.Signature) { + signBytes []byte, sig []byte) { pv.LastHeight = height pv.LastRound = round diff --git a/privval/priv_validator_test.go b/privval/priv_validator_test.go index 127f5c1f..b4f9ddbc 100644 --- a/privval/priv_validator_test.go +++ b/privval/priv_validator_test.go @@ -10,7 +10,6 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "github.com/tendermint/tendermint/crypto" "github.com/tendermint/tendermint/crypto/ed25519" "github.com/tendermint/tendermint/types" ) @@ -194,7 +193,7 @@ func TestDifferByTimestamp(t *testing.T) { // manipulate the timestamp. should get changed back proposal.Timestamp = proposal.Timestamp.Add(time.Millisecond) - var emptySig crypto.Signature + var emptySig []byte proposal.Signature = emptySig err = privVal.SignProposal("mychainid", proposal) assert.NoError(t, err, "expected no error on signing same proposal") @@ -218,7 +217,7 @@ func TestDifferByTimestamp(t *testing.T) { // manipulate the timestamp. should get changed back vote.Timestamp = vote.Timestamp.Add(time.Millisecond) - var emptySig crypto.Signature + var emptySig []byte vote.Signature = emptySig err = privVal.SignVote("mychainid", vote) assert.NoError(t, err, "expected no error on signing same vote") diff --git a/types/heartbeat.go b/types/heartbeat.go index cebe2864..151f1b0b 100644 --- a/types/heartbeat.go +++ b/types/heartbeat.go @@ -3,7 +3,6 @@ package types import ( "fmt" - "github.com/tendermint/tendermint/crypto" cmn "github.com/tendermint/tendermint/libs/common" ) @@ -13,12 +12,12 @@ import ( // json field tags because we always want the JSON // representation to be in its canonical form. type Heartbeat struct { - ValidatorAddress Address `json:"validator_address"` - ValidatorIndex int `json:"validator_index"` - Height int64 `json:"height"` - Round int `json:"round"` - Sequence int `json:"sequence"` - Signature crypto.Signature `json:"signature"` + ValidatorAddress Address `json:"validator_address"` + ValidatorIndex int `json:"validator_index"` + Height int64 `json:"height"` + Round int `json:"round"` + Sequence int `json:"sequence"` + Signature []byte `json:"signature"` } // SignBytes returns the Heartbeat bytes for signing. @@ -48,5 +47,6 @@ func (heartbeat *Heartbeat) String() string { return fmt.Sprintf("Heartbeat{%v:%X %v/%02d (%v) %v}", heartbeat.ValidatorIndex, cmn.Fingerprint(heartbeat.ValidatorAddress), - heartbeat.Height, heartbeat.Round, heartbeat.Sequence, heartbeat.Signature) + heartbeat.Height, heartbeat.Round, heartbeat.Sequence, + fmt.Sprintf("/%X.../", cmn.Fingerprint(heartbeat.Signature[:]))) } diff --git a/types/heartbeat_test.go b/types/heartbeat_test.go index f55c0bf3..ce9e4923 100644 --- a/types/heartbeat_test.go +++ b/types/heartbeat_test.go @@ -24,13 +24,13 @@ func TestHeartbeatString(t *testing.T) { require.Contains(t, nilHb.String(), "nil", "expecting a string and no panic") hb := &Heartbeat{ValidatorIndex: 1, Height: 11, Round: 2} - require.Equal(t, hb.String(), "Heartbeat{1:000000000000 11/02 (0) }") + require.Equal(t, "Heartbeat{1:000000000000 11/02 (0) /000000000000.../}", hb.String()) var key ed25519.PrivKeyEd25519 sig, err := key.Sign([]byte("Tendermint")) require.NoError(t, err) hb.Signature = sig - require.Equal(t, hb.String(), "Heartbeat{1:000000000000 11/02 (0) /FF41E371B9BF.../}") + require.Equal(t, "Heartbeat{1:000000000000 11/02 (0) /FF41E371B9BF.../}", hb.String()) } func TestHeartbeatWriteSignBytes(t *testing.T) { diff --git a/types/proposal.go b/types/proposal.go index 52ce8756..d5ae5492 100644 --- a/types/proposal.go +++ b/types/proposal.go @@ -4,8 +4,6 @@ import ( "errors" "fmt" "time" - - "github.com/tendermint/tendermint/crypto" ) var ( @@ -19,13 +17,13 @@ var ( // to be considered valid. It may depend on votes from a previous round, // a so-called Proof-of-Lock (POL) round, as noted in the POLRound and POLBlockID. type Proposal struct { - Height int64 `json:"height"` - Round int `json:"round"` - Timestamp time.Time `json:"timestamp"` - BlockPartsHeader PartSetHeader `json:"block_parts_header"` - POLRound int `json:"pol_round"` // -1 if null. - POLBlockID BlockID `json:"pol_block_id"` // zero if null. - Signature crypto.Signature `json:"signature"` + Height int64 `json:"height"` + Round int `json:"round"` + Timestamp time.Time `json:"timestamp"` + BlockPartsHeader PartSetHeader `json:"block_parts_header"` + POLRound int `json:"pol_round"` // -1 if null. + POLBlockID BlockID `json:"pol_block_id"` // zero if null. + Signature []byte `json:"signature"` } // NewProposal returns a new Proposal. diff --git a/types/proposal_test.go b/types/proposal_test.go index 8aef870f..b5c6bdce 100644 --- a/types/proposal_test.go +++ b/types/proposal_test.go @@ -39,7 +39,7 @@ func TestProposalSignable(t *testing.T) { func TestProposalString(t *testing.T) { str := testProposal.String() - expected := `Proposal{12345/23456 111:626C6F636B70 (-1,:0:000000000000) @ 2018-02-11T07:09:22.765Z}` + expected := `Proposal{12345/23456 111:626C6F636B70 (-1,:0:000000000000) [] @ 2018-02-11T07:09:22.765Z}` if str != expected { t.Errorf("Got unexpected string for Proposal. Expected:\n%v\nGot:\n%v", expected, str) } diff --git a/types/protobuf_test.go b/types/protobuf_test.go index 8711974e..6c9ba366 100644 --- a/types/protobuf_test.go +++ b/types/protobuf_test.go @@ -111,7 +111,7 @@ type pubKeyEddie struct{} func (pubKeyEddie) Address() Address { return []byte{} } func (pubKeyEddie) Bytes() []byte { return []byte{} } -func (pubKeyEddie) VerifyBytes(msg []byte, sig crypto.Signature) bool { return false } +func (pubKeyEddie) VerifyBytes(msg []byte, sig []byte) bool { return false } func (pubKeyEddie) Equals(crypto.PubKey) bool { return false } func TestABCIValidatorFromPubKeyAndPower(t *testing.T) { diff --git a/types/vote.go b/types/vote.go index ed4ebd73..a586615d 100644 --- a/types/vote.go +++ b/types/vote.go @@ -68,7 +68,7 @@ type Vote struct { Timestamp time.Time `json:"timestamp"` Type byte `json:"type"` BlockID BlockID `json:"block_id"` // zero if vote is nil. - Signature crypto.Signature `json:"signature"` + Signature []byte `json:"signature"` } func (vote *Vote) SignBytes(chainID string) []byte { diff --git a/types/vote_set.go b/types/vote_set.go index c5168105..36bf5ef7 100644 --- a/types/vote_set.go +++ b/types/vote_set.go @@ -179,7 +179,7 @@ func (voteSet *VoteSet) addVote(vote *Vote) (added bool, err error) { // If we already know of this vote, return false. if existing, ok := voteSet.getVote(valIndex, blockKey); ok { - if existing.Signature.Equals(vote.Signature) { + if bytes.Equal(existing.Signature, vote.Signature) { return false, nil // duplicate } return false, errors.Wrapf(ErrVoteNonDeterministicSignature, "Existing vote: %v; New vote: %v", existing, vote) From 8bd514d9fb1391511cca4b345ed6336995008c1c Mon Sep 17 00:00:00 2001 From: Ethan Buchman Date: Sun, 5 Aug 2018 15:45:52 -0400 Subject: [PATCH 4/5] update changelog --- CHANGELOG.md | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 957e749a..364af117 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,17 +4,25 @@ *August 5th, 2018* -This release includes a breaking upgrade to the p2p encryption and some minor -breaking changes in the ABCI. A few more changes are still coming to the Header, ABCI, +This release includes breaking upgrades in our P2P encryption, +some ABCI messages, and how we encode time and signatures. + +A few more changes are still coming to the Header, ABCI, and validator set handling to better support light clients, BFT time, and upgrades. Most notably, validator set changes will be delayed by one block (see -[#1815]). +[#1815][i1815]). + +We also removed `make ensure_deps` in favour of `make get_vendor_deps`. BREAKING CHANGES: - [abci] Changed time format from int64 to google.protobuf.Timestamp - [abci] Changed Validators to LastCommitInfo in RequestBeginBlock - [abci] Removed Fee from ResponseDeliverTx and ResponseCheckTx -- [p2p] Remove salsa and ripemd primitives, in favor of using chacha as a stream cipher, and hkdf +- [crypto] Switch crypto.Signature from interface to []byte for space efficiency + [#2128](https://github.com/tendermint/tendermint/pull/2128) + - NOTE: this means signatures no longer have the prefix bytes in Amino + binary nor the `type` field in Amino JSON. They're just bytes. +- [p2p] Remove salsa and ripemd primitives, in favor of using chacha as a stream cipher, and hkdf [#2054](https://github.com/tendermint/tendermint/pull/2054) - [tools] Removed `make ensure_deps` in favor of `make get_vendor_deps` - [types] CanonicalTime uses nanoseconds instead of clipping to ms - breaks serialization/signing of all messages with a timestamp @@ -26,6 +34,7 @@ FEATURES: IMPROVEMENTS: - [blockchain] Improve fast-sync logic + [#1805](https://github.com/tendermint/tendermint/pull/1805) - tweak params - only process one block at a time to avoid starving - [common] bit array functions which take in another parameter are now thread safe @@ -39,6 +48,8 @@ BUG FIXES: - [p2p] Allow startup if a configured seed node's IP can't be resolved ([#1716](https://github.com/tendermint/tendermint/issues/1716)) - [node] Fully exit when CTRL-C is pressed even if consensus state panics [#2072](https://github.com/tendermint/tendermint/issues/2072) +[i1815]: https://github.com/tendermint/tendermint/pull/1815 + ## 0.22.8 *July 26th, 2018* From 309a6772d7d04f1a2072191e030b86acf08c49ae Mon Sep 17 00:00:00 2001 From: Ethan Buchman Date: Sun, 5 Aug 2018 16:29:01 -0400 Subject: [PATCH 5/5] types: fix formatting when printing signatures - use cmn.Fingerprint and %X --- types/proposal.go | 7 +++++-- types/proposal_test.go | 2 +- types/vote.go | 21 +++++++++++---------- 3 files changed, 17 insertions(+), 13 deletions(-) diff --git a/types/proposal.go b/types/proposal.go index d5ae5492..81a5e2c3 100644 --- a/types/proposal.go +++ b/types/proposal.go @@ -4,6 +4,8 @@ import ( "errors" "fmt" "time" + + cmn "github.com/tendermint/tendermint/libs/common" ) var ( @@ -41,9 +43,10 @@ func NewProposal(height int64, round int, blockPartsHeader PartSetHeader, polRou // String returns a string representation of the Proposal. func (p *Proposal) String() string { - return fmt.Sprintf("Proposal{%v/%v %v (%v,%v) %v @ %s}", + return fmt.Sprintf("Proposal{%v/%v %v (%v,%v) %X @ %s}", p.Height, p.Round, p.BlockPartsHeader, p.POLRound, - p.POLBlockID, p.Signature, CanonicalTime(p.Timestamp)) + p.POLBlockID, + cmn.Fingerprint(p.Signature), CanonicalTime(p.Timestamp)) } // SignBytes returns the Proposal bytes for signing diff --git a/types/proposal_test.go b/types/proposal_test.go index b5c6bdce..7396fb76 100644 --- a/types/proposal_test.go +++ b/types/proposal_test.go @@ -39,7 +39,7 @@ func TestProposalSignable(t *testing.T) { func TestProposalString(t *testing.T) { str := testProposal.String() - expected := `Proposal{12345/23456 111:626C6F636B70 (-1,:0:000000000000) [] @ 2018-02-11T07:09:22.765Z}` + expected := `Proposal{12345/23456 111:626C6F636B70 (-1,:0:000000000000) 000000000000 @ 2018-02-11T07:09:22.765Z}` if str != expected { t.Errorf("Got unexpected string for Proposal. Expected:\n%v\nGot:\n%v", expected, str) } diff --git a/types/vote.go b/types/vote.go index a586615d..9a6180d7 100644 --- a/types/vote.go +++ b/types/vote.go @@ -61,14 +61,14 @@ type Address = cmn.HexBytes // Represents a prevote, precommit, or commit vote from validators for consensus. type Vote struct { - ValidatorAddress Address `json:"validator_address"` - ValidatorIndex int `json:"validator_index"` - Height int64 `json:"height"` - Round int `json:"round"` - Timestamp time.Time `json:"timestamp"` - Type byte `json:"type"` - BlockID BlockID `json:"block_id"` // zero if vote is nil. - Signature []byte `json:"signature"` + ValidatorAddress Address `json:"validator_address"` + ValidatorIndex int `json:"validator_index"` + Height int64 `json:"height"` + Round int `json:"round"` + Timestamp time.Time `json:"timestamp"` + Type byte `json:"type"` + BlockID BlockID `json:"block_id"` // zero if vote is nil. + Signature []byte `json:"signature"` } func (vote *Vote) SignBytes(chainID string) []byte { @@ -98,10 +98,11 @@ func (vote *Vote) String() string { cmn.PanicSanity("Unknown vote type") } - return fmt.Sprintf("Vote{%v:%X %v/%02d/%v(%v) %X %v @ %s}", + return fmt.Sprintf("Vote{%v:%X %v/%02d/%v(%v) %X %X @ %s}", vote.ValidatorIndex, cmn.Fingerprint(vote.ValidatorAddress), vote.Height, vote.Round, vote.Type, typeString, - cmn.Fingerprint(vote.BlockID.Hash), vote.Signature, + cmn.Fingerprint(vote.BlockID.Hash), + cmn.Fingerprint(vote.Signature), CanonicalTime(vote.Timestamp)) }