diff --git a/CHANGELOG.md b/CHANGELOG.md index cf0d7507b..4b77dbef5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,49 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## [Unreleased] +## [0.11.0] Kiviuq - 2024-02-21 [:boom:] +Exposure of protobuf converters & `SignedState`, abstraction of tests and bug fixes. + +## Added +- Add Fabric to backend list in README: [#377] +- Create new type `TransparentChannel` to expose `SignedState`: [#389] +- Update backend compatibility list in README: [#392] +- Add MAINTAINERS.md file, Update NOTICE: [#394] + +## Fixed +- Fix sub-channel test: [#359] +- Fix Multi-Adjudicator Subscription: [#366] +- Use correct identity for client tests: [#376] +- Fix link to white paper in README: [#379] +- Fix linter copyright year checking in CI: [#389] +- Fix failing unit tests: [#399] + +## Changed [:boom:] +- Abstract multiledger test, making it usable by backends: [#355] +- Abstract fund recovery test, making it usable by backends: [#370] +- Abstract virtual channel test, making it usable by backends: [#375] +- Expose protobuf converters: [#384] [#393] +- Use absolute module path in wire.proto: [#383] +- Create AppID Type to generalize app identifiers: [#378] [:boom:] + + +[#359]: https://github.com/hyperledger-labs/go-perun/pull/359 +[#355]: https://github.com/hyperledger-labs/go-perun/pull/355 +[#366]: https://github.com/hyperledger-labs/go-perun/pull/366 +[#370]: https://github.com/hyperledger-labs/go-perun/pull/370 +[#375]: https://github.com/hyperledger-labs/go-perun/pull/375 +[#376]: https://github.com/hyperledger-labs/go-perun/pull/376 +[#377]: https://github.com/hyperledger-labs/go-perun/pull/377 +[#378]: https://github.com/hyperledger-labs/go-perun/pull/378 +[#379]: https://github.com/hyperledger-labs/go-perun/pull/379 +[#383]: https://github.com/hyperledger-labs/go-perun/pull/383 +[#384]: https://github.com/hyperledger-labs/go-perun/pull/384 +[#389]: https://github.com/hyperledger-labs/go-perun/pull/389 +[#392]: https://github.com/hyperledger-labs/go-perun/pull/392 +[#393]: https://github.com/hyperledger-labs/go-perun/pull/393 +[#394]: https://github.com/hyperledger-labs/go-perun/pull/394 +[#399]: https://github.com/hyperledger-labs/go-perun/pull/399 + ## [0.10.0] Janus - 2022-05-25 [:warning:] Multi-ledger payment channels. @@ -389,7 +431,8 @@ Initial release. [:warning:]: #warning [:boom:]: #breaking -[Unreleased]: https://github.com/hyperledger-labs/go-perun/compare/v0.10.0...HEAD +[Unreleased]: https://github.com/hyperledger-labs/go-perun/compare/v0.11.0...HEAD +[0.11.0]: https://github.com/hyperledger-labs/go-perun/compare/v0.10.0...v0.11.0 [0.10.0]: https://github.com/hyperledger-labs/go-perun/compare/v0.9.1...v0.10.0 [0.9.1]: https://github.com/hyperledger-labs/go-perun/compare/v0.9.0...v0.9.1 [0.9.0]: https://github.com/hyperledger-labs/go-perun/compare/v0.8.0...v0.9.0 diff --git a/backend/sim/wire/account.go b/backend/sim/wire/account.go index ec5facba9..191cbcd17 100644 --- a/backend/sim/wire/account.go +++ b/backend/sim/wire/account.go @@ -30,6 +30,11 @@ func (acc *Account) Address() wire.Address { return acc.addr } +// Sign signs the given message with the account's private key. +func (acc *Account) Sign(msg []byte) ([]byte, error) { + return []byte("Authenticate"), nil +} + // NewRandomAccount generates a new random account. func NewRandomAccount(rng *rand.Rand) *Account { return &Account{ diff --git a/backend/sim/wire/address.go b/backend/sim/wire/address.go index 5db6d7d2d..4c241dc5c 100644 --- a/backend/sim/wire/address.go +++ b/backend/sim/wire/address.go @@ -16,6 +16,7 @@ package wire import ( "bytes" + "errors" "math/rand" "perun.network/go-perun/wire" @@ -62,6 +63,14 @@ func (a Address) Cmp(b wire.Address) int { return bytes.Compare(a[:], bTyped[:]) } +// Verify verifies a signature. +func (a Address) Verify(msg, sig []byte) error { + if !bytes.Equal(sig, []byte("Authenticate")) { + return errors.New("invalid signature") + } + return nil +} + // NewRandomAddress returns a new random peer address. func NewRandomAddress(rng *rand.Rand) *Address { addr := Address{} diff --git a/backend/sim/wire/doc.go b/backend/sim/wire/doc.go index fe538651f..5510f6939 100644 --- a/backend/sim/wire/doc.go +++ b/backend/sim/wire/doc.go @@ -12,5 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Package wire contains the implementation of the wire interfaces. +// Package wire is used for internal tests in the packages channel, wire, and client. +// Note that Account.Sign and Address.Verify are mock methods. +// We use the backend/wire/sim mock implementation for testing other go-perun functionalities. +// Our default wire.Account and wire.Address implementations can be found in wire/net/simple and are used for our applications. package wire // import "perun.network/go-perun/backend/sim/wire" diff --git a/client/adjudicate.go b/client/adjudicate.go index 7cdd616f2..362a8f294 100644 --- a/client/adjudicate.go +++ b/client/adjudicate.go @@ -270,7 +270,7 @@ func (c *Channel) Settle(ctx context.Context, secondary bool) (err error) { // Withdraw. err = c.withdraw(ctx, secondary) if err != nil { - return + return err } // Set phase `Withdrawn`. diff --git a/client/proposal.go b/client/proposal.go index d2762311a..39c524a2c 100644 --- a/client/proposal.go +++ b/client/proposal.go @@ -414,7 +414,7 @@ func (c *Client) validTwoPartyProposal( multiLedger := multi.IsMultiLedgerAssets(proposal.Base().InitBals.Assets) appChannel := !channel.IsNoApp(proposal.Base().App) if multiLedger && appChannel { - return fmt.Errorf("multi-ledger app channel not supported") + return errors.New("multi-ledger app channel not supported") } peers := c.proposalPeers(proposal) diff --git a/client/virtual_channel.go b/client/virtual_channel.go index 98723caf8..c903fc88f 100644 --- a/client/virtual_channel.go +++ b/client/virtual_channel.go @@ -348,7 +348,8 @@ func (c *Client) matchFundingProposal(ctx context.Context, a, b interface{}) boo } go func() { - err := virtual.watchVirtual() //nolint:contextcheck // The context will be derived from the channel context. + // The context will be derived from the channel context. + err := virtual.watchVirtual() //nolint:contextcheck c.log.Debugf("channel %v: watcher stopped: %v", virtual.ID(), err) }() return true diff --git a/go.mod b/go.mod index a765acf82..18373cc42 100644 --- a/go.mod +++ b/go.mod @@ -9,14 +9,13 @@ require ( go.uber.org/goleak v1.1.11 golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2 golang.org/x/sync v0.0.0-20210220032951-036812b2e83c - google.golang.org/protobuf v1.23.0 + google.golang.org/protobuf v1.32.0 polycry.pt/poly-go v0.0.0-20220222131629-aa4bdbaab60b ) require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/golang/snappy v0.0.4 // indirect - github.com/google/go-cmp v0.5.4 // indirect github.com/google/uuid v1.6.0 github.com/kr/text v0.2.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect diff --git a/go.sum b/go.sum index 80c0f338c..ba9700f3c 100644 --- a/go.sum +++ b/go.sum @@ -12,13 +12,14 @@ github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrU github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.4 h1:L8R9j+yAqZuZjsqh/z+F1NCffTKKLShY6zXTItVIZ8M= -github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= @@ -116,8 +117,10 @@ google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= -google.golang.org/protobuf v1.23.0 h1:4MY060fB1DLGMB/7MBTLnwQUY6+F09GEiz6SsrNqyzM= google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.32.0 h1:pPC6BG5ex8PDFnkbrGU3EixyhKcQ2aDuBS36lqK/C7I= +google.golang.org/protobuf v1.32.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= diff --git a/wallet/test/address.go b/wallet/test/address.go index 99b9efde7..bbd45ab7f 100644 --- a/wallet/test/address.go +++ b/wallet/test/address.go @@ -34,8 +34,8 @@ func TestAddress(t *testing.T, s *Setup) { //nolint:revive // `test.Test...` stu // Test Address.String. nullString := null.String() addrString := addr.String() - assert.Greater(t, len(nullString), 0) - assert.Greater(t, len(addrString), 0) + assert.NotEmpty(t, nullString) + assert.NotEmpty(t, addrString) assert.NotEqual(t, addrString, nullString) // Test Address.Equals. diff --git a/wallet/test/wallet.go b/wallet/test/wallet.go index 804182cef..83d469076 100644 --- a/wallet/test/wallet.go +++ b/wallet/test/wallet.go @@ -75,7 +75,7 @@ func TestAccountWithWalletAndBackend(t *testing.T, s *Setup) { //nolint:revive / t.Error("Verification of invalid signature should produce error or return false") } // Expand the signature and check for error - // nolint:gocritic + //nolint:gocritic tampered = append(sig, 0) valid, err = s.Backend.VerifySignature(s.DataToSign, tampered, acc.Address()) if valid && err != nil { diff --git a/wallet/test/walletbench.go b/wallet/test/walletbench.go index 0630769b0..5ba272bae 100644 --- a/wallet/test/walletbench.go +++ b/wallet/test/walletbench.go @@ -30,7 +30,7 @@ func GenericAccountBenchmark(b *testing.B, s *Setup) { func benchAccountSign(b *testing.B, s *Setup) { b.Helper() perunAcc, err := s.Wallet.Unlock(s.AddressInWallet) - require.Nil(b, err) + require.NoError(b, err) for n := 0; n < b.N; n++ { _, err := perunAcc.SignData(s.DataToSign) @@ -56,9 +56,9 @@ func benchBackendVerifySig(b *testing.B, s *Setup) { // We dont want to measure the SignDataWithPW here, just need it for the verification b.StopTimer() perunAcc, err := s.Wallet.Unlock(s.AddressInWallet) - require.Nil(b, err) + require.NoError(b, err) signature, err := perunAcc.SignData(s.DataToSign) - require.Nil(b, err) + require.NoError(b, err) b.StartTimer() for n := 0; n < b.N; n++ { diff --git a/wire/account.go b/wire/account.go index 195476177..d8e2dc908 100644 --- a/wire/account.go +++ b/wire/account.go @@ -15,6 +15,8 @@ package wire import ( + "encoding/binary" + "fmt" "io" ) @@ -31,14 +33,17 @@ func init() { type Account interface { // Address used by this account. Address() Address + + // Sign signs the given message with this account's private key. + Sign(msg []byte) ([]byte, error) } var _ Msg = (*AuthResponseMsg)(nil) // AuthResponseMsg is the response message in the peer authentication protocol. -// -// This will be expanded later to contain signatures. -type AuthResponseMsg struct{} +type AuthResponseMsg struct { + Signature []byte +} // Type returns AuthResponse. func (m *AuthResponseMsg) Type() Type { @@ -46,16 +51,46 @@ func (m *AuthResponseMsg) Type() Type { } // Encode encodes this AuthResponseMsg into an io.Writer. +// It writes the signature to the writer. func (m *AuthResponseMsg) Encode(w io.Writer) error { - return nil + // Write the length of the signature + err := binary.Write(w, binary.BigEndian, uint32(len(m.Signature))) + if err != nil { + return fmt.Errorf("failed to write signature length: %w", err) + } + // Write the signature itself + _, err = w.Write(m.Signature) + return err } // Decode decodes an AuthResponseMsg from an io.Reader. +// It reads the signature from the reader. func (m *AuthResponseMsg) Decode(r io.Reader) (err error) { + // Read the length of the signature + var signatureLen uint32 + if err := binary.Read(r, binary.BigEndian, &signatureLen); err != nil { + return fmt.Errorf("failed to read signature length: %w", err) + } + // Read the signature bytes + m.Signature = make([]byte, signatureLen) + if _, err := io.ReadFull(r, m.Signature); err != nil { + return fmt.Errorf("failed to read signature: %w", err) + } return nil } // NewAuthResponseMsg creates an authentication response message. -func NewAuthResponseMsg(_ Account) Msg { - return &AuthResponseMsg{} +func NewAuthResponseMsg(acc Account) (Msg, error) { + addressBytes, err := acc.Address().MarshalBinary() + if err != nil { + return nil, fmt.Errorf("failed to marshal address: %w", err) + } + signature, err := acc.Sign(addressBytes) + if err != nil { + return nil, fmt.Errorf("failed to sign address: %w", err) + } + + return &AuthResponseMsg{ + Signature: signature, + }, nil } diff --git a/wire/address.go b/wire/address.go index 890436d09..de48ab1ec 100644 --- a/wire/address.go +++ b/wire/address.go @@ -41,6 +41,9 @@ type Address interface { // Cmp compares the byte representation of two addresses. For `a.Cmp(b)` // returns -1 if a < b, 0 if a == b, 1 if a > b. Cmp(Address) int + // Verify verifies a message signature. + // It returns an error if the signature is invalid. + Verify(msg []byte, sig []byte) error } // Addresses is a helper type for encoding and decoding address slices in diff --git a/wire/cache_internal_test.go b/wire/cache_internal_test.go index 8d45d6b76..4de3acff7 100644 --- a/wire/cache_internal_test.go +++ b/wire/cache_internal_test.go @@ -56,7 +56,7 @@ func TestCache(t *testing.T) { assert.Equal(2, c.Size()) empty := c.Messages(func(*Envelope) bool { return false }) - assert.Len(empty, 0) + assert.Empty(empty) c.Release(&isPing) assert.False(c.Put(ping2), "Put into cache with canceled predicate") diff --git a/wire/net/exchange_addr.go b/wire/net/exchange_addr.go index 634939db6..658052f0d 100644 --- a/wire/net/exchange_addr.go +++ b/wire/net/exchange_addr.go @@ -59,10 +59,15 @@ func IsAuthenticationError(err error) bool { func ExchangeAddrsActive(ctx context.Context, id wire.Account, peer wire.Address, conn Conn) error { var err error ok := pkg.TerminatesCtx(ctx, func() { + authMsg, err2 := wire.NewAuthResponseMsg(id) + if err2 != nil { + err = errors.WithMessage(err2, "creating auth message") + return + } err = conn.Send(&wire.Envelope{ Sender: id.Address(), Recipient: peer, - Msg: wire.NewAuthResponseMsg(id), + Msg: authMsg, }) if err != nil { err = errors.WithMessage(err, "sending message") @@ -74,6 +79,8 @@ func ExchangeAddrsActive(ctx context.Context, id wire.Account, peer wire.Address err = errors.WithMessage(err, "receiving message") } else if _, ok := e.Msg.(*wire.AuthResponseMsg); !ok { err = errors.Errorf("expected AuthResponse wire msg, got %v", e.Msg.Type()) + } else if check := VerifyAddressSignature(peer, e.Msg.(*wire.AuthResponseMsg).Signature); check != nil { + err = errors.WithMessage(err, "verifying peer address's signature") } else if !e.Recipient.Equal(id.Address()) && !e.Sender.Equal(peer) { err = NewAuthenticationError(e.Sender, e.Recipient, id.Address(), "unmatched response sender or recipient") @@ -101,14 +108,23 @@ func ExchangeAddrsPassive(ctx context.Context, id wire.Account, conn Conn) (wire err = errors.Errorf("expected AuthResponse wire msg, got %v", e.Msg.Type()) } else if !e.Recipient.Equal(id.Address()) { err = NewAuthenticationError(e.Sender, e.Recipient, id.Address(), "unmatched response sender or recipient") + } else if err = VerifyAddressSignature(e.Sender, e.Msg.(*wire.AuthResponseMsg).Signature); err != nil { + err = errors.WithMessage(err, "verifying peer address's signature") } + if err != nil { return } + + authMsg, err2 := wire.NewAuthResponseMsg(id) + if err2 != nil { + err = errors.WithMessage(err2, "creating auth message") + return + } addr, err = e.Sender, conn.Send(&wire.Envelope{ Sender: id.Address(), Recipient: e.Sender, - Msg: wire.NewAuthResponseMsg(id), + Msg: authMsg, }) }) @@ -120,3 +136,14 @@ func ExchangeAddrsPassive(ctx context.Context, id wire.Account, conn Conn) (wire } return addr, err } + +// VerifyAddressSignature verifies a signature against the hash of an address. +// It relies on the MarshalBinary method of the provided wire.Address interface to generate the address hash. +// In case the MarshalBinary method doesn't produce the expected hash, the verification may fail. +func VerifyAddressSignature(addr wire.Address, sig []byte) error { + addressBytes, err := addr.MarshalBinary() + if err != nil { + return fmt.Errorf("failed to marshal address: %w", err) + } + return addr.Verify(addressBytes, sig) +} diff --git a/wire/net/simple/account.go b/wire/net/simple/account.go index b1999cf10..799a59ab6 100644 --- a/wire/net/simple/account.go +++ b/wire/net/simple/account.go @@ -15,21 +15,20 @@ package simple import ( + "crypto" + crypto_rand "crypto/rand" + "crypto/rsa" + "crypto/sha256" "math/rand" + "github.com/pkg/errors" "perun.network/go-perun/wire" ) // Account is a wire account. type Account struct { - addr wire.Address -} - -// NewAccount creates a new account. -func NewAccount(addr *Address) *Account { - return &Account{ - addr: addr, - } + addr wire.Address + privateKey *rsa.PrivateKey } // Address returns the account's address. @@ -37,9 +36,32 @@ func (acc *Account) Address() wire.Address { return acc.addr } +// Sign signs the given message with the account's private key. +func (acc *Account) Sign(msg []byte) ([]byte, error) { + if acc.privateKey == nil { + return nil, errors.New("private key is nil") + } + hashed := sha256.Sum256(msg) + signature, err := rsa.SignPKCS1v15(crypto_rand.Reader, acc.privateKey, crypto.SHA256, hashed[:]) + if err != nil { + return nil, err + } + return signature, nil +} + // NewRandomAccount generates a new random account. func NewRandomAccount(rng *rand.Rand) *Account { + keySize := 2048 + privateKey, err := rsa.GenerateKey(rng, keySize) + if err != nil { + panic(err) + } + + address := NewRandomAddress(rng) + address.PublicKey = &privateKey.PublicKey + return &Account{ - addr: NewRandomAddress(rng), + addr: address, + privateKey: privateKey, } } diff --git a/wire/net/simple/address.go b/wire/net/simple/address.go index 3cc962df2..7ed03e226 100644 --- a/wire/net/simple/address.go +++ b/wire/net/simple/address.go @@ -16,54 +16,165 @@ package simple import ( "bytes" + "crypto" + "crypto/rsa" + "crypto/sha256" + "encoding/binary" + "math/big" "math/rand" "perun.network/go-perun/wire" ) // Address is a wire address. -type Address string - -var _ wire.Address = NewAddress("") +type Address struct { + Name string + PublicKey *rsa.PublicKey // Public key for verifying signatures +} // NewAddress returns a new address. func NewAddress(host string) *Address { - a := Address(host) - return &a + return &Address{ + Name: host, + } } // MarshalBinary marshals the address to binary. -func (a Address) MarshalBinary() ([]byte, error) { - buf := make([]byte, len(a)) - copy(buf, []byte(a)) - return buf, nil +func (a *Address) MarshalBinary() ([]byte, error) { + // Initialize a buffer to hold the binary data + var buf bytes.Buffer + + // Encode the length of the name string and the name itself + nameLen := uint16(len(a.Name)) + if err := binary.Write(&buf, binary.BigEndian, nameLen); err != nil { + return nil, err + } + if _, err := buf.WriteString(a.Name); err != nil { + return nil, err + } + + // If the public key is not nil, encode it + if a.PublicKey != nil { + if err := encodePublicKey(&buf, a.PublicKey); err != nil { + return nil, err + } + } + + // Return the binary representation + return buf.Bytes(), nil } // UnmarshalBinary unmarshals an address from binary. func (a *Address) UnmarshalBinary(data []byte) error { - buf := make([]byte, len(data)) - copy(buf, data) - *a = Address(buf) + // Initialize a buffer with the binary data + buf := bytes.NewBuffer(data) + + // Decode the length of the name string + var nameLen uint16 + if err := binary.Read(buf, binary.BigEndian, &nameLen); err != nil { + return err + } + + // Read the name string from the buffer + nameBytes := make([]byte, nameLen) + if _, err := buf.Read(nameBytes); err != nil { + return err + } + a.Name = string(nameBytes) + + // Check if there's remaining data for the public key + if buf.Len() > 0 { + // Decode the public key + a.PublicKey = &rsa.PublicKey{} + if err := decodePublicKey(buf, a.PublicKey); err != nil { + return err + } + } + + return nil +} + +// encodePublicKey encodes the public key into the buffer. +func encodePublicKey(buf *bytes.Buffer, key *rsa.PublicKey) error { + // Encode modulus length and modulus + modulusBytes := key.N.Bytes() + modulusLen := uint16(len(modulusBytes)) + if err := binary.Write(buf, binary.BigEndian, modulusLen); err != nil { + return err + } + if err := binary.Write(buf, binary.BigEndian, modulusBytes); err != nil { + return err + } + + // Encode public exponent + if err := binary.Write(buf, binary.BigEndian, int32(key.E)); err != nil { + return err + } + + return nil +} + +// decodePublicKey decodes the public key from the buffer. +func decodePublicKey(buf *bytes.Buffer, key *rsa.PublicKey) error { + // Decode modulus length + var modulusLen uint16 + if err := binary.Read(buf, binary.BigEndian, &modulusLen); err != nil { + return err + } + + // Decode modulus + modulusBytes := make([]byte, modulusLen) + if _, err := buf.Read(modulusBytes); err != nil { + return err + } + key.N = new(big.Int).SetBytes(modulusBytes) + + // Decode public exponent + var publicExponent int32 + if err := binary.Read(buf, binary.BigEndian, &publicExponent); err != nil { + return err + } + key.E = int(publicExponent) + return nil } // Equal returns whether the two addresses are equal. -func (a Address) Equal(b wire.Address) bool { +func (a *Address) Equal(b wire.Address) bool { bTyped, ok := b.(*Address) if !ok { return false } - return a == *bTyped + if a.PublicKey == nil { + return a.Name == bTyped.Name && bTyped.PublicKey == nil + } + + return a.Name == bTyped.Name && a.PublicKey.Equal(bTyped.PublicKey) } -// Cmp compares the byte representation of two addresses. For `a.Cmp(b)` -// returns -1 if a < b, 0 if a == b, 1 if a > b. -func (a Address) Cmp(b wire.Address) int { +// Cmp compares the byte representation of two addresses. +// It first checks if the types match, then compares the byte representations of their names. +// It returns the result of comparing the byte representations of the addresses: +// +// -1 if a's byte representation is less than b's, +// 0 if they are equal, +// 1 if a's byte representation is greater than b's. +// +// It panics if the type assertion fails or if there's an error while marshaling. +func (a *Address) Cmp(b wire.Address) int { + // Type assertion to ensure b is of type *Address bTyped, ok := b.(*Address) if !ok { panic("wrong type") } - return bytes.Compare([]byte(a), []byte(*bTyped)) + + // Compare names + if cmp := bytes.Compare([]byte(a.Name), []byte(bTyped.Name)); cmp != 0 { + return cmp + } + + // Compare binary representations + return bytes.Compare([]byte(a.Name), []byte(bTyped.Name)) } // NewRandomAddress returns a new random peer address. @@ -75,6 +186,18 @@ func NewRandomAddress(rng *rand.Rand) *Address { panic(err) } - a := Address(d) - return &a + a := &Address{ + Name: string(d), + } + return a +} + +// Verify verifies a message signature. +func (a *Address) Verify(msg []byte, sig []byte) error { + hashed := sha256.Sum256(msg) + err := rsa.VerifyPKCS1v15(a.PublicKey, crypto.SHA256, hashed[:], sig) + if err != nil { + return err + } + return nil } diff --git a/wire/net/simple/dialer.go b/wire/net/simple/dialer.go index 37de0d342..82016ef27 100644 --- a/wire/net/simple/dialer.go +++ b/wire/net/simple/dialer.go @@ -16,6 +16,7 @@ package simple import ( "context" + "crypto/tls" "net" "sync" "time" @@ -31,7 +32,7 @@ import ( type Dialer struct { mutex sync.RWMutex // Protects peers. peers map[wire.AddrKey]string // Known peer addresses. - dialer net.Dialer // Used to dial connections. + dialer tls.Dialer // Used to dial connections. network string // The socket type. pkgsync.Closer @@ -44,22 +45,27 @@ var _ wirenet.Dialer = (*Dialer)(nil) // timeouts may still apply even when no timeout is selected. The network string // controls the type of connection that the dialer can dial. // `serializer` defines the message encoding. -func NewNetDialer(network string, defaultTimeout time.Duration) *Dialer { +func NewNetDialer(network string, defaultTimeout time.Duration, tlsConfig *tls.Config) *Dialer { + netDialer := &net.Dialer{Timeout: defaultTimeout} + return &Dialer{ - peers: make(map[wire.AddrKey]string), - dialer: net.Dialer{Timeout: defaultTimeout}, + peers: make(map[wire.AddrKey]string), + dialer: tls.Dialer{ + NetDialer: netDialer, + Config: tlsConfig, + }, network: network, } } // NewTCPDialer is a short-hand version of NewNetDialer for creating TCP dialers. -func NewTCPDialer(defaultTimeout time.Duration) *Dialer { - return NewNetDialer("tcp", defaultTimeout) +func NewTCPDialer(defaultTimeout time.Duration, tlsConfig *tls.Config) *Dialer { + return NewNetDialer("tcp", defaultTimeout, tlsConfig) } // NewUnixDialer is a short-hand version of NewNetDialer for creating Unix dialers. -func NewUnixDialer(defaultTimeout time.Duration) *Dialer { - return NewNetDialer("unix", defaultTimeout) +func NewUnixDialer(defaultTimeout time.Duration, tlsConfig *tls.Config) *Dialer { + return NewNetDialer("unix", defaultTimeout, tlsConfig) } func (d *Dialer) host(key wire.AddrKey) (string, bool) { diff --git a/wire/net/simple/dialer_internal_test.go b/wire/net/simple/dialer_internal_test.go index b5e382b3a..a493eb9fb 100644 --- a/wire/net/simple/dialer_internal_test.go +++ b/wire/net/simple/dialer_internal_test.go @@ -16,6 +16,15 @@ package simple import ( "context" + "crypto/rand" + "crypto/rsa" + "crypto/tls" + "crypto/x509" + "crypto/x509/pkix" + "encoding/pem" + "fmt" + "math/big" + "net" "testing" "time" @@ -30,20 +39,29 @@ import ( ) func TestNewTCPDialer(t *testing.T) { - d := NewTCPDialer(0) + tlsConfig := &tls.Config{ + MinVersion: tls.VersionTLS12, // Set minimum TLS version to TLS 1.2 + } + d := NewTCPDialer(0, tlsConfig) assert.Equal(t, d.network, "tcp") } func TestNewUnixDialer(t *testing.T) { - d := NewUnixDialer(0) + tlsConfig := &tls.Config{ + MinVersion: tls.VersionTLS12, // Set minimum TLS version to TLS 1.2 + } + d := NewUnixDialer(0, tlsConfig) assert.Equal(t, d.network, "unix") } func TestDialer_Register(t *testing.T) { + tlsConfig := &tls.Config{ + MinVersion: tls.VersionTLS12, // Set minimum TLS version to TLS 1.2 + } rng := test.Prng(t) - addr := wiretest.NewRandomAddress(rng) + addr := NewRandomAddress(rng) key := wire.Key(addr) - d := NewTCPDialer(0) + d := NewTCPDialer(0, tlsConfig) _, ok := d.host(key) require.False(t, ok) @@ -59,16 +77,21 @@ func TestDialer_Dial(t *testing.T) { timeout := 100 * time.Millisecond rng := test.Prng(t) lhost := "127.0.0.1:7357" - laddr := wiretest.NewRandomAddress(rng) + laddr := wiretest.NewRandomAccount(rng).Address() - l, err := NewTCPListener(lhost) + commonName := "127.0.0.1" + sans := []string{"127.0.0.1", "localhost"} + lConfig, dConfig, err := generateSelfSignedCertConfigs(commonName, sans) + require.NoError(t, err, "failed to generate self-signed certificate configs") + + l, err := NewTCPListener(lhost, lConfig) require.NoError(t, err) defer l.Close() ser := perunio.Serializer() - d := NewTCPDialer(timeout) + d := NewTCPDialer(timeout, dConfig) d.Register(laddr, lhost) - daddr := wiretest.NewRandomAddress(rng) + daddr := wiretest.NewRandomAccount(rng).Address() defer d.Close() t.Run("happy", func(t *testing.T) { @@ -112,7 +135,7 @@ func TestDialer_Dial(t *testing.T) { }) t.Run("unknown host", func(t *testing.T) { - noHostAddr := wiretest.NewRandomAddress(rng) + noHostAddr := NewRandomAddress(rng) d.Register(noHostAddr, "no such host") ctxtest.AssertTerminates(t, timeout, func() { @@ -124,10 +147,129 @@ func TestDialer_Dial(t *testing.T) { t.Run("unknown address", func(t *testing.T) { ctxtest.AssertTerminates(t, timeout, func() { - unkownAddr := wiretest.NewRandomAddress(rng) + unkownAddr := NewRandomAddress(rng) conn, err := d.Dial(context.Background(), unkownAddr, ser) assert.Error(t, err) assert.Nil(t, conn) }) }) } + +// generateSelfSignedCertConfigs generates a self-signed certificate and returns +// the server and client TLS configurations. +func generateSelfSignedCertConfigs(commonName string, sans []string) (*tls.Config, *tls.Config, error) { + keySize := 2048 + // Generate a new RSA private key for the server + serverPrivateKey, err := rsa.GenerateKey(rand.Reader, keySize) + if err != nil { + return nil, nil, err + } + + // Generate a new RSA private key for the client + clientPrivateKey, err := rsa.GenerateKey(rand.Reader, keySize) + if err != nil { + return nil, nil, err + } + + // Create a certificate template for the server + serverTemplate := x509.Certificate{ + SerialNumber: big.NewInt(1), + Subject: pkix.Name{ + Organization: []string{"Perun Network"}, + CommonName: commonName, + }, + NotBefore: time.Now(), + NotAfter: time.Now().Add(24 * time.Hour), + KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature, + ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth}, + BasicConstraintsValid: true, + } + + // Add SANs to the server certificate template + for _, san := range sans { + if ip := net.ParseIP(san); ip != nil { + serverTemplate.IPAddresses = append(serverTemplate.IPAddresses, ip) + } else { + serverTemplate.DNSNames = append(serverTemplate.DNSNames, san) + } + } + + // Generate a self-signed server certificate + serverCertDER, err := x509.CreateCertificate(rand.Reader, &serverTemplate, &serverTemplate, &serverPrivateKey.PublicKey, serverPrivateKey) + if err != nil { + return nil, nil, err + } + + // Encode the server certificate to PEM format + serverCertPEM := pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: serverCertDER}) + + // Encode the server private key to PEM format + serverKeyPEM := pem.EncodeToMemory(&pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(serverPrivateKey)}) + + // Create a tls.Certificate object for the server + serverCert, err := tls.X509KeyPair(serverCertPEM, serverKeyPEM) + if err != nil { + return nil, nil, err + } + + // Create a certificate template for the client + clientTemplate := x509.Certificate{ + SerialNumber: big.NewInt(1), + Subject: pkix.Name{ + Organization: []string{"Perun Network"}, + CommonName: commonName, // Change this to the client's common name + }, + NotBefore: time.Now(), + NotAfter: time.Now().Add(24 * time.Hour), + KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature, + ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth}, // Set the client authentication usage + BasicConstraintsValid: true, + } + + // Generate a self-signed client certificate + clientCertDER, err := x509.CreateCertificate(rand.Reader, &clientTemplate, &clientTemplate, &clientPrivateKey.PublicKey, serverPrivateKey) + if err != nil { + return nil, nil, err + } + + // Encode the client certificate to PEM format + clientCertPEM := pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: clientCertDER}) + + // Encode the client private key to PEM format + clientKeyPEM := pem.EncodeToMemory(&pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(clientPrivateKey)}) + + // Create a tls.Certificate object for the client + clientCert, err := tls.X509KeyPair(clientCertPEM, clientKeyPEM) + if err != nil { + return nil, nil, err + } + + serverCertPool := x509.NewCertPool() + ok := serverCertPool.AppendCertsFromPEM(clientCertPEM) + if !ok { + return nil, nil, fmt.Errorf("failed to parse root certificate") + } + + // Create the server-side TLS configuration + serverConfig := &tls.Config{ + ClientCAs: serverCertPool, + Certificates: []tls.Certificate{serverCert}, + ClientAuth: tls.RequireAndVerifyClientCert, + MinVersion: tls.VersionTLS12, // Set minimum TLS version to TLS 1.2 + } + + clientCertPool := x509.NewCertPool() + ok = clientCertPool.AppendCertsFromPEM(serverCertPEM) + if !ok { + return nil, nil, fmt.Errorf("failed to parse root certificate") + } + + // Create the client-side TLS configuration + clientConfig := &tls.Config{ + RootCAs: clientCertPool, + Certificates: []tls.Certificate{clientCert}, + MinVersion: tls.VersionTLS12, // Set minimum TLS version to TLS 1.2 + } + + return serverConfig, clientConfig, nil +} diff --git a/wire/net/simple/doc.go b/wire/net/simple/doc.go index 9e72316c0..fc3a32331 100644 --- a/wire/net/simple/doc.go +++ b/wire/net/simple/doc.go @@ -12,6 +12,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Package simple contains simplistic implementation for the wire.Dialer and -// wire.Listener interfaces. +// Package simple contains a simplistic implementation for the wire.Dialer and +// wire.Listener interfaces. It uses TLS to ensure secure peer connection. package simple // import "perun.network/go-perun/wire/net/simple" diff --git a/wire/net/simple/init.go b/wire/net/simple/init.go index cce04c416..2f77391a5 100644 --- a/wire/net/simple/init.go +++ b/wire/net/simple/init.go @@ -25,9 +25,11 @@ func init() { wire.SetNewAddressFunc(func() wire.Address { return NewAddress("") }) + // Setup for testing purposes. test.SetNewRandomAddress(func(rng *rand.Rand) wire.Address { return NewRandomAddress(rng) }) + // Setup for testing purposes. test.SetNewRandomAccount(func(rng *rand.Rand) wire.Account { return NewRandomAccount(rng) }) diff --git a/wire/net/simple/listener.go b/wire/net/simple/listener.go index 34aed5576..9a3954998 100644 --- a/wire/net/simple/listener.go +++ b/wire/net/simple/listener.go @@ -15,6 +15,7 @@ package simple import ( + "crypto/tls" "net" "github.com/pkg/errors" @@ -30,8 +31,8 @@ type Listener struct { var _ wirenet.Listener = (*Listener)(nil) // NewNetListener creates a listener reachable under the requested address. -func NewNetListener(network string, address string) (*Listener, error) { - l, err := net.Listen(network, address) +func NewNetListener(network string, address string, config *tls.Config) (*Listener, error) { + l, err := tls.Listen(network, address, config) if err != nil { return nil, errors.Wrapf(err, "failed to create listener for '%s'", address) @@ -41,13 +42,13 @@ func NewNetListener(network string, address string) (*Listener, error) { } // NewTCPListener is a short-hand version of NewNetListener for TCP listeners. -func NewTCPListener(address string) (*Listener, error) { - return NewNetListener("tcp", address) +func NewTCPListener(address string, config *tls.Config) (*Listener, error) { + return NewNetListener("tcp", address, config) } // NewUnixListener is a short-hand version of NewNetListener for Unix listeners. -func NewUnixListener(address string) (*Listener, error) { - return NewNetListener("unix", address) +func NewUnixListener(address string, config *tls.Config) (*Listener, error) { + return NewNetListener("unix", address, config) } // Accept implements peer.Dialer.Accept(). diff --git a/wire/net/simple/listener_internal_test.go b/wire/net/simple/listener_internal_test.go index c37a64702..b5cc7258b 100644 --- a/wire/net/simple/listener_internal_test.go +++ b/wire/net/simple/listener_internal_test.go @@ -15,6 +15,7 @@ package simple import ( + "crypto/tls" "testing" "time" @@ -27,21 +28,67 @@ import ( const addr = "0.0.0.0:1337" +// serverKey and serverCert are generated with the following commands: +// openssl ecparam -genkey -name prime256v1 -out server.key +// openssl req -new -x509 -key server.key -out server.pem -days 3650. +const testServerKey = `-----BEGIN EC PARAMETERS----- +BggqhkjOPQMBBw== +-----END EC PARAMETERS----- +-----BEGIN EC PRIVATE KEY----- +MHcCAQEEIHg+g2unjA5BkDtXSN9ShN7kbPlbCcqcYdDu+QeV8XWuoAoGCCqGSM49 +AwEHoUQDQgAEcZpodWh3SEs5Hh3rrEiu1LZOYSaNIWO34MgRxvqwz1FMpLxNlx0G +cSqrxhPubawptX5MSr02ft32kfOlYbaF5Q== +-----END EC PRIVATE KEY----- +` + +const testServerCert = `-----BEGIN CERTIFICATE----- +MIIB+TCCAZ+gAwIBAgIJAL05LKXo6PrrMAoGCCqGSM49BAMCMFkxCzAJBgNVBAYT +AkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBXaWRn +aXRzIFB0eSBMdGQxEjAQBgNVBAMMCWxvY2FsaG9zdDAeFw0xNTEyMDgxNDAxMTNa +Fw0yNTEyMDUxNDAxMTNaMFkxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0 +YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQxEjAQBgNVBAMM +CWxvY2FsaG9zdDBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABHGaaHVod0hLOR4d +66xIrtS2TmEmjSFjt+DIEcb6sM9RTKS8TZcdBnEqq8YT7m2sKbV+TEq9Nn7d9pHz +pWG2heWjUDBOMB0GA1UdDgQWBBR0fqrecDJ44D/fiYJiOeBzfoqEijAfBgNVHSME +GDAWgBR0fqrecDJ44D/fiYJiOeBzfoqEijAMBgNVHRMEBTADAQH/MAoGCCqGSM49 +BAMCA0gAMEUCIEKzVMF3JqjQjuM2rX7Rx8hancI5KJhwfeKu1xbyR7XaAiEA2UT7 +1xOP035EcraRmWPe7tO0LpXgMxlh2VItpc2uc2w= +-----END CERTIFICATE----- +` + func TestNewTCPListener(t *testing.T) { - l, err := NewTCPListener(addr) + cer, err := tls.X509KeyPair([]byte(testServerCert), []byte(testServerKey)) + require.NoError(t, err, "loading server key and cert") + tlsConfig := &tls.Config{ + MinVersion: tls.VersionTLS12, // Set minimum TLS version to TLS 1.2 + Certificates: []tls.Certificate{cer}, + } + l, err := NewTCPListener(addr, tlsConfig) require.NoError(t, err) defer l.Close() } func TestNewUnixListener(t *testing.T) { - l, err := NewUnixListener(addr) + cer, err := tls.X509KeyPair([]byte(testServerCert), []byte(testServerKey)) + require.NoError(t, err, "loading server key and cert") + tlsConfig := &tls.Config{ + MinVersion: tls.VersionTLS12, // Set minimum TLS version to TLS 1.2 + Certificates: []tls.Certificate{cer}, + } + l, err := NewUnixListener(addr, tlsConfig) require.NoError(t, err) defer l.Close() } func TestListener_Close(t *testing.T) { + cer, err := tls.X509KeyPair([]byte(testServerCert), []byte(testServerKey)) + require.NoError(t, err, "loading server key and cert") + tlsConfig := &tls.Config{ + MinVersion: tls.VersionTLS12, // Set minimum TLS version to TLS 1.2 + Certificates: []tls.Certificate{cer}, + } t.Run("double close", func(t *testing.T) { - l, err := NewTCPListener(addr) + l, err := NewTCPListener(addr, tlsConfig) require.NoError(t, err) assert.NoError(t, l.Close(), "first close must not return error") assert.Error(t, l.Close(), "second close must result in error") @@ -49,35 +96,46 @@ func TestListener_Close(t *testing.T) { } func TestNewListener(t *testing.T) { + cer, err := tls.X509KeyPair([]byte(testServerCert), []byte(testServerKey)) + require.NoError(t, err, "loading server key and cert") + tlsConfig := &tls.Config{ + MinVersion: tls.VersionTLS12, // Set minimum TLS version to TLS 1.2 + Certificates: []tls.Certificate{cer}, + } t.Run("happy", func(t *testing.T) { - l, err := NewTCPListener(addr) + l, err := NewTCPListener(addr, tlsConfig) assert.NoError(t, err) require.NotNil(t, l) l.Close() }) t.Run("sad", func(t *testing.T) { - l, err := NewTCPListener("not an address") + l, err := NewTCPListener("not an address", tlsConfig) assert.Error(t, err) assert.Nil(t, l) }) t.Run("address in use", func(t *testing.T) { - l, err := NewTCPListener(addr) + l, err := NewTCPListener(addr, tlsConfig) require.NoError(t, err) - _, err = NewTCPListener(addr) + _, err = NewTCPListener(addr, tlsConfig) require.Error(t, err) l.Close() }) } func TestListener_Accept(t *testing.T) { + cer, err := tls.X509KeyPair([]byte(testServerCert), []byte(testServerKey)) + require.NoError(t, err, "loading server key and cert") + tlsConfig := &tls.Config{ + MinVersion: tls.VersionTLS12, // Set minimum TLS version to TLS 1.2 + Certificates: []tls.Certificate{cer}, + } // Happy case already tested in TestDialer_Dial. - ser := perunio.Serializer() timeout := 100 * time.Millisecond t.Run("timeout", func(t *testing.T) { - l, err := NewTCPListener(addr) + l, err := NewTCPListener(addr, tlsConfig) require.NoError(t, err) defer l.Close() @@ -87,7 +145,7 @@ func TestListener_Accept(t *testing.T) { }) t.Run("closed", func(t *testing.T) { - l, err := NewTCPListener(addr) + l, err := NewTCPListener(addr, tlsConfig) require.NoError(t, err) l.Close() diff --git a/wire/net/simple/mockconn_internal_test.go b/wire/net/simple/mockconn_internal_test.go new file mode 100644 index 000000000..73350efcb --- /dev/null +++ b/wire/net/simple/mockconn_internal_test.go @@ -0,0 +1,68 @@ +// Copyright 2019 - See NOTICE file for copyright holders. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package simple + +import ( + "sync" + + "github.com/pkg/errors" + + "perun.network/go-perun/wire" + wirenet "perun.network/go-perun/wire/net" + "polycry.pt/poly-go/sync/atomic" +) + +var _ wirenet.Conn = (*MockConn)(nil) + +type MockConn struct { + mutex sync.Mutex + closed atomic.Bool + recvQueue chan *wire.Envelope + + sent func(*wire.Envelope) // observes sent messages. +} + +func newMockConn() *MockConn { + return &MockConn{ + sent: func(*wire.Envelope) {}, + recvQueue: make(chan *wire.Envelope, 1), + } +} + +func (c *MockConn) Send(e *wire.Envelope) error { + c.mutex.Lock() + defer c.mutex.Unlock() + if c.closed.IsSet() { + return errors.New("closed") + } + c.sent(e) + return nil +} + +func (c *MockConn) Recv() (*wire.Envelope, error) { + c.mutex.Lock() + defer c.mutex.Unlock() + if c.closed.IsSet() { + return nil, errors.New("closed") + } + return <-c.recvQueue, nil +} + +func (c *MockConn) Close() error { + if !c.closed.TrySet() { + return errors.New("double close") + } + return nil +} diff --git a/wire/net/simple/simple_exchange_addr_test.go b/wire/net/simple/simple_exchange_addr_test.go new file mode 100644 index 000000000..4dbd13646 --- /dev/null +++ b/wire/net/simple/simple_exchange_addr_test.go @@ -0,0 +1,112 @@ +// Copyright 2020 - See NOTICE file for copyright holders. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// This test uses the wire/net/simple implementation of Account and Address +// to test the default implementation of wire. +// +//nolint:testpackage +package simple + +import ( + "context" + "math/rand" + "net" + "sync" + "testing" + "time" + + "github.com/stretchr/testify/assert" + + "perun.network/go-perun/wire" + wirenet "perun.network/go-perun/wire/net" + perunio "perun.network/go-perun/wire/perunio/serializer" + wiretest "perun.network/go-perun/wire/test" + ctxtest "polycry.pt/poly-go/context/test" + "polycry.pt/poly-go/test" +) + +const timeout = 100 * time.Millisecond + +func TestExchangeAddrs_ConnFail(t *testing.T) { + rng := test.Prng(t) + a, _ := newPipeConnPair() + a.Close() + addr, err := wirenet.ExchangeAddrsPassive(context.Background(), wiretest.NewRandomAccount(rng), a) + assert.Nil(t, addr) + assert.Error(t, err) +} + +func TestExchangeAddrs_Success(t *testing.T) { + rng := test.Prng(t) + conn0, conn1 := newPipeConnPair() + defer conn0.Close() + account0, account1 := wiretest.NewRandomAccount(rng), wiretest.NewRandomAccount(rng) + var wg sync.WaitGroup + wg.Add(1) + + go func() { + defer wg.Done() + defer conn1.Close() + + recvAddr0, err := wirenet.ExchangeAddrsPassive(context.Background(), account1, conn1) + assert.NoError(t, err) + assert.True(t, recvAddr0.Equal(account0.Address())) + }() + + err := wirenet.ExchangeAddrsActive(context.Background(), account0, account1.Address(), conn0) + assert.NoError(t, err) + + wg.Wait() +} + +func TestExchangeAddrs_Timeout(t *testing.T) { + rng := test.Prng(t) + a, _ := newPipeConnPair() + + ctx, cancel := context.WithTimeout(context.Background(), timeout) + defer cancel() + ctxtest.AssertTerminates(t, 20*timeout, func() { + addr, err := wirenet.ExchangeAddrsPassive(ctx, wiretest.NewRandomAccount(rng), a) + assert.Nil(t, addr) + assert.Error(t, err) + }) +} + +func TestExchangeAddrs_BogusMsg(t *testing.T) { + rng := test.Prng(t) + acc := wiretest.NewRandomAccount(rng) + conn := newMockConn() + conn.recvQueue <- newRandomEnvelope(rng, wire.NewPingMsg()) + addr, err := wirenet.ExchangeAddrsPassive(context.Background(), acc, conn) + + assert.Error(t, err, "ExchangeAddrs should error when peer sends a non-AuthResponseMsg") + assert.Nil(t, addr) +} + +// newPipeConnPair creates endpoints that are connected via pipes. +func newPipeConnPair() (a wirenet.Conn, b wirenet.Conn) { + c0, c1 := net.Pipe() + ser := perunio.Serializer() + return wirenet.NewIoConn(c0, ser), wirenet.NewIoConn(c1, ser) +} + +// NewRandomEnvelope returns an envelope around message m with random sender and +// recipient generated using randomness from rng. +func newRandomEnvelope(rng *rand.Rand, m wire.Msg) *wire.Envelope { + return &wire.Envelope{ + Sender: NewRandomAddress(rng), + Recipient: NewRandomAddress(rng), + Msg: m, + } +} diff --git a/wire/perunio/serialize.go b/wire/perunio/serialize.go index 0672478d6..259e0e805 100644 --- a/wire/perunio/serialize.go +++ b/wire/perunio/serialize.go @@ -56,7 +56,7 @@ func Encode(writer io.Writer, values ...interface{}) (err error) { //nolint: cyc length := len(data) if length > uint16MaxValue { - panic(fmt.Sprintf("lenth of marshaled data is %d, should be <= %d", len(data), uint16MaxValue)) + panic(fmt.Sprintf("length of marshaled data is %d, should be <= %d", len(data), uint16MaxValue)) } err = binary.Write(writer, byteOrder, uint16(length)) if err != nil { diff --git a/wire/perunio/string.go b/wire/perunio/string.go index 277bea229..292c0a837 100644 --- a/wire/perunio/string.go +++ b/wire/perunio/string.go @@ -42,7 +42,7 @@ func encodeString(w io.Writer, s string) error { return errors.Wrap(err, "failed to write string") } -// decodeString reads the length as uint16 and the the string itself from the io.Reader. +// decodeString reads the length as uint16 and the string itself from the io.Reader. func decodeString(r io.Reader, s *string) error { var l uint16 if err := binary.Read(r, byteOrder, &l); err != nil { diff --git a/wire/perunio/string_internal_test.go b/wire/perunio/string_internal_test.go index 7df9d0207..4310ec9a8 100644 --- a/wire/perunio/string_internal_test.go +++ b/wire/perunio/string_internal_test.go @@ -54,7 +54,7 @@ func TestEncodeDecodeString(t *testing.T) { }) t.Run("too long string", func(t *testing.T) { - tooLong := string(append(uint16buf, 42)) // nolint: makezero + tooLong := string(append(uint16buf, 42)) //nolint: makezero var buf bytes.Buffer assert.Error(encodeString(&buf, tooLong)) assert.Zero(buf.Len(), "nothing should have been written to the stream") diff --git a/wire/perunio/test/serializertest.go b/wire/perunio/test/serializertest.go index ac5f04d8d..709f5eec9 100644 --- a/wire/perunio/test/serializertest.go +++ b/wire/perunio/test/serializertest.go @@ -34,6 +34,7 @@ func GenericSerializerTest(t *testing.T, serializers ...perunio.Serializer) { // genericDecodeEncodeTest tests whether encoding and then decoding // serializer values results in the original values. +// //nolint:thelper // The linter thinks this is a helper, but it isn't. func genericDecodeEncodeTest(t *testing.T, serializers ...perunio.Serializer) { for i, v := range serializers { @@ -60,6 +61,7 @@ func genericDecodeEncodeTest(t *testing.T, serializers ...perunio.Serializer) { // GenericBrokenPipeTest tests that encoding and decoding on broken streams // fails. +// //nolint:thelper // The linter thinks this is a helper, but it isn't. func GenericBrokenPipeTest(t *testing.T, serializers ...perunio.Serializer) { for i, v := range serializers { diff --git a/wire/perunio/wire_internal_test.go b/wire/perunio/wire_internal_test.go index f8c2d001b..4d9640a46 100644 --- a/wire/perunio/wire_internal_test.go +++ b/wire/perunio/wire_internal_test.go @@ -85,7 +85,7 @@ func TestEncodeDecode(t *testing.T) { } go func() { - a.Nil(Encode(w, values...), "failed to encode values") + a.NoError(Encode(w, values...), "failed to encode values") }() d := make([]interface{}, len(values)) diff --git a/wire/protobuf/controlmsgs.go b/wire/protobuf/controlmsgs.go index ed907af63..f363b982f 100644 --- a/wire/protobuf/controlmsgs.go +++ b/wire/protobuf/controlmsgs.go @@ -38,6 +38,12 @@ func fromShutdownMsg(msg *wire.ShutdownMsg) *Envelope_ShutdownMsg { return &Envelope_ShutdownMsg{protoMsg} } +func fromAuthResponseMsg(msg *wire.AuthResponseMsg) *Envelope_AuthResponseMsg { + protoMsg := &AuthResponseMsg{} + protoMsg.Signature = msg.Signature + return &Envelope_AuthResponseMsg{protoMsg} +} + func toPingMsg(protoMsg *Envelope_PingMsg) (msg *wire.PingMsg) { msg = &wire.PingMsg{} msg.Created = time.Unix(0, protoMsg.PingMsg.Created) @@ -55,3 +61,9 @@ func toShutdownMsg(protoEnvMsg *Envelope_ShutdownMsg) (msg *wire.ShutdownMsg) { msg.Reason = protoEnvMsg.ShutdownMsg.Reason return msg } + +func toAuthResponseMsg(protoEnvMsg *Envelope_AuthResponseMsg) (msg *wire.AuthResponseMsg) { + msg = &wire.AuthResponseMsg{} + msg.Signature = protoEnvMsg.AuthResponseMsg.Signature + return msg +} diff --git a/wire/protobuf/serializer.go b/wire/protobuf/serializer.go index cd7b284f5..ef18432f8 100644 --- a/wire/protobuf/serializer.go +++ b/wire/protobuf/serializer.go @@ -45,7 +45,7 @@ func (serializer) Encode(w io.Writer, env *wire.Envelope) (err error) { //nolint case *wire.ShutdownMsg: protoEnv.Msg = fromShutdownMsg(msg) case *wire.AuthResponseMsg: - protoEnv.Msg = &Envelope_AuthResponseMsg{} + protoEnv.Msg = fromAuthResponseMsg(msg) case *client.LedgerChannelProposalMsg: protoEnv.Msg, err = FromLedgerChannelProposalMsg(msg) case *client.SubChannelProposalMsg: @@ -131,7 +131,7 @@ func (serializer) Decode(r io.Reader) (env *wire.Envelope, err error) { //nolint case *Envelope_ShutdownMsg: env.Msg = toShutdownMsg(protoMsg) case *Envelope_AuthResponseMsg: - env.Msg = &wire.AuthResponseMsg{} + env.Msg = toAuthResponseMsg(protoMsg) case *Envelope_LedgerChannelProposalMsg: env.Msg, err = ToLedgerChannelProposalMsg(protoMsg) case *Envelope_SubChannelProposalMsg: diff --git a/wire/protobuf/wire.pb.go b/wire/protobuf/wire.pb.go index 71204dc8a..49a605f46 100644 --- a/wire/protobuf/wire.pb.go +++ b/wire/protobuf/wire.pb.go @@ -17,7 +17,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.27.1 -// protoc v3.12.4 +// protoc v4.25.2 // source: wire.proto package protobuf @@ -1285,6 +1285,8 @@ type AuthResponseMsg struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields + + Signature []byte `protobuf:"bytes,1,opt,name=signature,proto3" json:"signature,omitempty"` } func (x *AuthResponseMsg) Reset() { @@ -1319,6 +1321,13 @@ func (*AuthResponseMsg) Descriptor() ([]byte, []int) { return file_wire_proto_rawDescGZIP(), []int{16} } +func (x *AuthResponseMsg) GetSignature() []byte { + if x != nil { + return x.Signature + } + return nil +} + // LedgerChannelProposalMsg represents client.LedgerChannelProposalMsg. type LedgerChannelProposalMsg struct { state protoimpl.MessageState @@ -2300,124 +2309,128 @@ var file_wire_proto_rawDesc = []byte{ 0x28, 0x03, 0x52, 0x07, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x22, 0x25, 0x0a, 0x0b, 0x53, 0x68, 0x75, 0x74, 0x64, 0x6f, 0x77, 0x6e, 0x4d, 0x73, 0x67, 0x12, 0x16, 0x0a, 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x72, 0x65, 0x61, 0x73, - 0x6f, 0x6e, 0x22, 0x11, 0x0a, 0x0f, 0x41, 0x75, 0x74, 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x4d, 0x73, 0x67, 0x22, 0xa6, 0x01, 0x0a, 0x18, 0x4c, 0x65, 0x64, 0x67, 0x65, 0x72, - 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x50, 0x72, 0x6f, 0x70, 0x6f, 0x73, 0x61, 0x6c, 0x4d, - 0x73, 0x67, 0x12, 0x52, 0x0a, 0x15, 0x62, 0x61, 0x73, 0x65, 0x5f, 0x63, 0x68, 0x61, 0x6e, 0x6e, - 0x65, 0x6c, 0x5f, 0x70, 0x72, 0x6f, 0x70, 0x6f, 0x73, 0x61, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x1e, 0x2e, 0x70, 0x65, 0x72, 0x75, 0x6e, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x42, 0x61, - 0x73, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x50, 0x72, 0x6f, 0x70, 0x6f, 0x73, 0x61, - 0x6c, 0x52, 0x13, 0x62, 0x61, 0x73, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x50, 0x72, - 0x6f, 0x70, 0x6f, 0x73, 0x61, 0x6c, 0x12, 0x20, 0x0a, 0x0b, 0x70, 0x61, 0x72, 0x74, 0x69, 0x63, - 0x69, 0x70, 0x61, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0b, 0x70, 0x61, 0x72, - 0x74, 0x69, 0x63, 0x69, 0x70, 0x61, 0x6e, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x70, 0x65, 0x65, 0x72, - 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x05, 0x70, 0x65, 0x65, 0x72, 0x73, 0x22, 0x9d, - 0x01, 0x0a, 0x1b, 0x4c, 0x65, 0x64, 0x67, 0x65, 0x72, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, + 0x6f, 0x6e, 0x22, 0x2f, 0x0a, 0x0f, 0x41, 0x75, 0x74, 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x4d, 0x73, 0x67, 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, + 0x72, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, + 0x75, 0x72, 0x65, 0x22, 0xa6, 0x01, 0x0a, 0x18, 0x4c, 0x65, 0x64, 0x67, 0x65, 0x72, 0x43, 0x68, + 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x50, 0x72, 0x6f, 0x70, 0x6f, 0x73, 0x61, 0x6c, 0x4d, 0x73, 0x67, + 0x12, 0x52, 0x0a, 0x15, 0x62, 0x61, 0x73, 0x65, 0x5f, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, + 0x5f, 0x70, 0x72, 0x6f, 0x70, 0x6f, 0x73, 0x61, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x1e, 0x2e, 0x70, 0x65, 0x72, 0x75, 0x6e, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x42, 0x61, 0x73, 0x65, + 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x50, 0x72, 0x6f, 0x70, 0x6f, 0x73, 0x61, 0x6c, 0x52, + 0x13, 0x62, 0x61, 0x73, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x50, 0x72, 0x6f, 0x70, + 0x6f, 0x73, 0x61, 0x6c, 0x12, 0x20, 0x0a, 0x0b, 0x70, 0x61, 0x72, 0x74, 0x69, 0x63, 0x69, 0x70, + 0x61, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0b, 0x70, 0x61, 0x72, 0x74, 0x69, + 0x63, 0x69, 0x70, 0x61, 0x6e, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x70, 0x65, 0x65, 0x72, 0x73, 0x18, + 0x03, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x05, 0x70, 0x65, 0x65, 0x72, 0x73, 0x22, 0x9d, 0x01, 0x0a, + 0x1b, 0x4c, 0x65, 0x64, 0x67, 0x65, 0x72, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x50, 0x72, + 0x6f, 0x70, 0x6f, 0x73, 0x61, 0x6c, 0x41, 0x63, 0x63, 0x4d, 0x73, 0x67, 0x12, 0x5c, 0x0a, 0x19, + 0x62, 0x61, 0x73, 0x65, 0x5f, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x5f, 0x70, 0x72, 0x6f, + 0x70, 0x6f, 0x73, 0x61, 0x6c, 0x5f, 0x61, 0x63, 0x63, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x21, 0x2e, 0x70, 0x65, 0x72, 0x75, 0x6e, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x42, 0x61, 0x73, 0x65, + 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x50, 0x72, 0x6f, 0x70, 0x6f, 0x73, 0x61, 0x6c, 0x41, + 0x63, 0x63, 0x52, 0x16, 0x62, 0x61, 0x73, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x50, + 0x72, 0x6f, 0x70, 0x6f, 0x73, 0x61, 0x6c, 0x41, 0x63, 0x63, 0x12, 0x20, 0x0a, 0x0b, 0x70, 0x61, + 0x72, 0x74, 0x69, 0x63, 0x69, 0x70, 0x61, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, + 0x0b, 0x70, 0x61, 0x72, 0x74, 0x69, 0x63, 0x69, 0x70, 0x61, 0x6e, 0x74, 0x22, 0x83, 0x01, 0x0a, + 0x15, 0x53, 0x75, 0x62, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x50, 0x72, 0x6f, 0x70, 0x6f, + 0x73, 0x61, 0x6c, 0x4d, 0x73, 0x67, 0x12, 0x52, 0x0a, 0x15, 0x62, 0x61, 0x73, 0x65, 0x5f, 0x63, + 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x5f, 0x70, 0x72, 0x6f, 0x70, 0x6f, 0x73, 0x61, 0x6c, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x70, 0x65, 0x72, 0x75, 0x6e, 0x77, 0x69, 0x72, + 0x65, 0x2e, 0x42, 0x61, 0x73, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x50, 0x72, 0x6f, + 0x70, 0x6f, 0x73, 0x61, 0x6c, 0x52, 0x13, 0x62, 0x61, 0x73, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x6e, + 0x65, 0x6c, 0x50, 0x72, 0x6f, 0x70, 0x6f, 0x73, 0x61, 0x6c, 0x12, 0x16, 0x0a, 0x06, 0x70, 0x61, + 0x72, 0x65, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x70, 0x61, 0x72, 0x65, + 0x6e, 0x74, 0x22, 0x78, 0x0a, 0x18, 0x53, 0x75, 0x62, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x50, 0x72, 0x6f, 0x70, 0x6f, 0x73, 0x61, 0x6c, 0x41, 0x63, 0x63, 0x4d, 0x73, 0x67, 0x12, 0x5c, 0x0a, 0x19, 0x62, 0x61, 0x73, 0x65, 0x5f, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x5f, 0x70, 0x72, 0x6f, 0x70, 0x6f, 0x73, 0x61, 0x6c, 0x5f, 0x61, 0x63, 0x63, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x70, 0x65, 0x72, 0x75, 0x6e, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x42, 0x61, 0x73, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x50, 0x72, 0x6f, 0x70, 0x6f, 0x73, 0x61, 0x6c, 0x41, 0x63, 0x63, 0x52, 0x16, 0x62, 0x61, 0x73, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, - 0x6c, 0x50, 0x72, 0x6f, 0x70, 0x6f, 0x73, 0x61, 0x6c, 0x41, 0x63, 0x63, 0x12, 0x20, 0x0a, 0x0b, - 0x70, 0x61, 0x72, 0x74, 0x69, 0x63, 0x69, 0x70, 0x61, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x0c, 0x52, 0x0b, 0x70, 0x61, 0x72, 0x74, 0x69, 0x63, 0x69, 0x70, 0x61, 0x6e, 0x74, 0x22, 0x83, - 0x01, 0x0a, 0x15, 0x53, 0x75, 0x62, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x50, 0x72, 0x6f, - 0x70, 0x6f, 0x73, 0x61, 0x6c, 0x4d, 0x73, 0x67, 0x12, 0x52, 0x0a, 0x15, 0x62, 0x61, 0x73, 0x65, - 0x5f, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x5f, 0x70, 0x72, 0x6f, 0x70, 0x6f, 0x73, 0x61, - 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x70, 0x65, 0x72, 0x75, 0x6e, 0x77, - 0x69, 0x72, 0x65, 0x2e, 0x42, 0x61, 0x73, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x50, - 0x72, 0x6f, 0x70, 0x6f, 0x73, 0x61, 0x6c, 0x52, 0x13, 0x62, 0x61, 0x73, 0x65, 0x43, 0x68, 0x61, - 0x6e, 0x6e, 0x65, 0x6c, 0x50, 0x72, 0x6f, 0x70, 0x6f, 0x73, 0x61, 0x6c, 0x12, 0x16, 0x0a, 0x06, - 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x70, 0x61, - 0x72, 0x65, 0x6e, 0x74, 0x22, 0x78, 0x0a, 0x18, 0x53, 0x75, 0x62, 0x43, 0x68, 0x61, 0x6e, 0x6e, - 0x65, 0x6c, 0x50, 0x72, 0x6f, 0x70, 0x6f, 0x73, 0x61, 0x6c, 0x41, 0x63, 0x63, 0x4d, 0x73, 0x67, - 0x12, 0x5c, 0x0a, 0x19, 0x62, 0x61, 0x73, 0x65, 0x5f, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, - 0x5f, 0x70, 0x72, 0x6f, 0x70, 0x6f, 0x73, 0x61, 0x6c, 0x5f, 0x61, 0x63, 0x63, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x70, 0x65, 0x72, 0x75, 0x6e, 0x77, 0x69, 0x72, 0x65, 0x2e, - 0x42, 0x61, 0x73, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x50, 0x72, 0x6f, 0x70, 0x6f, - 0x73, 0x61, 0x6c, 0x41, 0x63, 0x63, 0x52, 0x16, 0x62, 0x61, 0x73, 0x65, 0x43, 0x68, 0x61, 0x6e, - 0x6e, 0x65, 0x6c, 0x50, 0x72, 0x6f, 0x70, 0x6f, 0x73, 0x61, 0x6c, 0x41, 0x63, 0x63, 0x22, 0xef, - 0x01, 0x0a, 0x19, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, - 0x6c, 0x50, 0x72, 0x6f, 0x70, 0x6f, 0x73, 0x61, 0x6c, 0x4d, 0x73, 0x67, 0x12, 0x52, 0x0a, 0x15, - 0x62, 0x61, 0x73, 0x65, 0x5f, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x5f, 0x70, 0x72, 0x6f, - 0x70, 0x6f, 0x73, 0x61, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x70, 0x65, - 0x72, 0x75, 0x6e, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x42, 0x61, 0x73, 0x65, 0x43, 0x68, 0x61, 0x6e, - 0x6e, 0x65, 0x6c, 0x50, 0x72, 0x6f, 0x70, 0x6f, 0x73, 0x61, 0x6c, 0x52, 0x13, 0x62, 0x61, 0x73, - 0x65, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x50, 0x72, 0x6f, 0x70, 0x6f, 0x73, 0x61, 0x6c, - 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x72, 0x6f, 0x70, 0x6f, 0x73, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x0c, 0x52, 0x08, 0x70, 0x72, 0x6f, 0x70, 0x6f, 0x73, 0x65, 0x72, 0x12, 0x14, 0x0a, 0x05, - 0x70, 0x65, 0x65, 0x72, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x05, 0x70, 0x65, 0x65, - 0x72, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x04, 0x20, - 0x03, 0x28, 0x0c, 0x52, 0x07, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x32, 0x0a, 0x0a, - 0x69, 0x6e, 0x64, 0x65, 0x78, 0x5f, 0x6d, 0x61, 0x70, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, - 0x32, 0x13, 0x2e, 0x70, 0x65, 0x72, 0x75, 0x6e, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x49, 0x6e, 0x64, - 0x65, 0x78, 0x4d, 0x61, 0x70, 0x52, 0x09, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x4d, 0x61, 0x70, 0x73, - 0x22, 0x9a, 0x01, 0x0a, 0x1c, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x43, 0x68, 0x61, 0x6e, - 0x6e, 0x65, 0x6c, 0x50, 0x72, 0x6f, 0x70, 0x6f, 0x73, 0x61, 0x6c, 0x41, 0x63, 0x63, 0x4d, 0x73, - 0x67, 0x12, 0x5c, 0x0a, 0x19, 0x62, 0x61, 0x73, 0x65, 0x5f, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, - 0x6c, 0x5f, 0x70, 0x72, 0x6f, 0x70, 0x6f, 0x73, 0x61, 0x6c, 0x5f, 0x61, 0x63, 0x63, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x70, 0x65, 0x72, 0x75, 0x6e, 0x77, 0x69, 0x72, 0x65, - 0x2e, 0x42, 0x61, 0x73, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x50, 0x72, 0x6f, 0x70, - 0x6f, 0x73, 0x61, 0x6c, 0x41, 0x63, 0x63, 0x52, 0x16, 0x62, 0x61, 0x73, 0x65, 0x43, 0x68, 0x61, - 0x6e, 0x6e, 0x65, 0x6c, 0x50, 0x72, 0x6f, 0x70, 0x6f, 0x73, 0x61, 0x6c, 0x41, 0x63, 0x63, 0x12, - 0x1c, 0x0a, 0x09, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x64, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x0c, 0x52, 0x09, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x64, 0x65, 0x72, 0x22, 0x50, 0x0a, - 0x15, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x50, 0x72, 0x6f, 0x70, 0x6f, 0x73, 0x61, 0x6c, - 0x52, 0x65, 0x6a, 0x4d, 0x73, 0x67, 0x12, 0x1f, 0x0a, 0x0b, 0x70, 0x72, 0x6f, 0x70, 0x6f, 0x73, - 0x61, 0x6c, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0a, 0x70, 0x72, 0x6f, - 0x70, 0x6f, 0x73, 0x61, 0x6c, 0x49, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, - 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x22, - 0x65, 0x0a, 0x10, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, - 0x4d, 0x73, 0x67, 0x12, 0x3f, 0x0a, 0x0e, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x5f, 0x75, - 0x70, 0x64, 0x61, 0x74, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x70, 0x65, - 0x72, 0x75, 0x6e, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x55, - 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x0d, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x55, 0x70, - 0x64, 0x61, 0x74, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x73, 0x69, 0x67, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x0c, 0x52, 0x03, 0x73, 0x69, 0x67, 0x22, 0xd1, 0x01, 0x0a, 0x20, 0x56, 0x69, 0x72, 0x74, 0x75, - 0x61, 0x6c, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x46, 0x75, 0x6e, 0x64, 0x69, 0x6e, 0x67, - 0x50, 0x72, 0x6f, 0x70, 0x6f, 0x73, 0x61, 0x6c, 0x4d, 0x73, 0x67, 0x12, 0x49, 0x0a, 0x12, 0x63, - 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x5f, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x5f, 0x6d, 0x73, - 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x70, 0x65, 0x72, 0x75, 0x6e, 0x77, - 0x69, 0x72, 0x65, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x55, 0x70, 0x64, 0x61, 0x74, - 0x65, 0x4d, 0x73, 0x67, 0x52, 0x10, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x55, 0x70, 0x64, - 0x61, 0x74, 0x65, 0x4d, 0x73, 0x67, 0x12, 0x30, 0x0a, 0x07, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x61, - 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x70, 0x65, 0x72, 0x75, 0x6e, 0x77, - 0x69, 0x72, 0x65, 0x2e, 0x53, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, - 0x07, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x6c, 0x12, 0x30, 0x0a, 0x09, 0x69, 0x6e, 0x64, 0x65, - 0x78, 0x5f, 0x6d, 0x61, 0x70, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x70, 0x65, - 0x72, 0x75, 0x6e, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x4d, 0x61, 0x70, - 0x52, 0x08, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x4d, 0x61, 0x70, 0x22, 0x9e, 0x01, 0x0a, 0x23, 0x56, - 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x53, 0x65, 0x74, - 0x74, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x50, 0x72, 0x6f, 0x70, 0x6f, 0x73, 0x61, 0x6c, 0x4d, - 0x73, 0x67, 0x12, 0x49, 0x0a, 0x12, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x5f, 0x75, 0x70, - 0x64, 0x61, 0x74, 0x65, 0x5f, 0x6d, 0x73, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, - 0x2e, 0x70, 0x65, 0x72, 0x75, 0x6e, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x6e, - 0x65, 0x6c, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4d, 0x73, 0x67, 0x52, 0x10, 0x63, 0x68, 0x61, - 0x6e, 0x6e, 0x65, 0x6c, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4d, 0x73, 0x67, 0x12, 0x2c, 0x0a, - 0x05, 0x66, 0x69, 0x6e, 0x61, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x70, - 0x65, 0x72, 0x75, 0x6e, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x53, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x53, - 0x74, 0x61, 0x74, 0x65, 0x52, 0x05, 0x66, 0x69, 0x6e, 0x61, 0x6c, 0x22, 0x60, 0x0a, 0x13, 0x43, - 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x41, 0x63, 0x63, 0x4d, + 0x6c, 0x50, 0x72, 0x6f, 0x70, 0x6f, 0x73, 0x61, 0x6c, 0x41, 0x63, 0x63, 0x22, 0xef, 0x01, 0x0a, + 0x19, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x50, + 0x72, 0x6f, 0x70, 0x6f, 0x73, 0x61, 0x6c, 0x4d, 0x73, 0x67, 0x12, 0x52, 0x0a, 0x15, 0x62, 0x61, + 0x73, 0x65, 0x5f, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x5f, 0x70, 0x72, 0x6f, 0x70, 0x6f, + 0x73, 0x61, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x70, 0x65, 0x72, 0x75, + 0x6e, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x42, 0x61, 0x73, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, + 0x6c, 0x50, 0x72, 0x6f, 0x70, 0x6f, 0x73, 0x61, 0x6c, 0x52, 0x13, 0x62, 0x61, 0x73, 0x65, 0x43, + 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x50, 0x72, 0x6f, 0x70, 0x6f, 0x73, 0x61, 0x6c, 0x12, 0x1a, + 0x0a, 0x08, 0x70, 0x72, 0x6f, 0x70, 0x6f, 0x73, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, + 0x52, 0x08, 0x70, 0x72, 0x6f, 0x70, 0x6f, 0x73, 0x65, 0x72, 0x12, 0x14, 0x0a, 0x05, 0x70, 0x65, + 0x65, 0x72, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x05, 0x70, 0x65, 0x65, 0x72, 0x73, + 0x12, 0x18, 0x0a, 0x07, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, + 0x0c, 0x52, 0x07, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x32, 0x0a, 0x0a, 0x69, 0x6e, + 0x64, 0x65, 0x78, 0x5f, 0x6d, 0x61, 0x70, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x13, + 0x2e, 0x70, 0x65, 0x72, 0x75, 0x6e, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x49, 0x6e, 0x64, 0x65, 0x78, + 0x4d, 0x61, 0x70, 0x52, 0x09, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x4d, 0x61, 0x70, 0x73, 0x22, 0x9a, + 0x01, 0x0a, 0x1c, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, + 0x6c, 0x50, 0x72, 0x6f, 0x70, 0x6f, 0x73, 0x61, 0x6c, 0x41, 0x63, 0x63, 0x4d, 0x73, 0x67, 0x12, + 0x5c, 0x0a, 0x19, 0x62, 0x61, 0x73, 0x65, 0x5f, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x5f, + 0x70, 0x72, 0x6f, 0x70, 0x6f, 0x73, 0x61, 0x6c, 0x5f, 0x61, 0x63, 0x63, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x70, 0x65, 0x72, 0x75, 0x6e, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x42, + 0x61, 0x73, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x50, 0x72, 0x6f, 0x70, 0x6f, 0x73, + 0x61, 0x6c, 0x41, 0x63, 0x63, 0x52, 0x16, 0x62, 0x61, 0x73, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x6e, + 0x65, 0x6c, 0x50, 0x72, 0x6f, 0x70, 0x6f, 0x73, 0x61, 0x6c, 0x41, 0x63, 0x63, 0x12, 0x1c, 0x0a, + 0x09, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x64, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, + 0x52, 0x09, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x64, 0x65, 0x72, 0x22, 0x50, 0x0a, 0x15, 0x43, + 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x50, 0x72, 0x6f, 0x70, 0x6f, 0x73, 0x61, 0x6c, 0x52, 0x65, + 0x6a, 0x4d, 0x73, 0x67, 0x12, 0x1f, 0x0a, 0x0b, 0x70, 0x72, 0x6f, 0x70, 0x6f, 0x73, 0x61, 0x6c, + 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0a, 0x70, 0x72, 0x6f, 0x70, 0x6f, + 0x73, 0x61, 0x6c, 0x49, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x22, 0x65, 0x0a, + 0x10, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4d, 0x73, + 0x67, 0x12, 0x3f, 0x0a, 0x0e, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x5f, 0x75, 0x70, 0x64, + 0x61, 0x74, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x70, 0x65, 0x72, 0x75, + 0x6e, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x55, 0x70, 0x64, + 0x61, 0x74, 0x65, 0x52, 0x0d, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x55, 0x70, 0x64, 0x61, + 0x74, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x73, 0x69, 0x67, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, + 0x03, 0x73, 0x69, 0x67, 0x22, 0xd1, 0x01, 0x0a, 0x20, 0x56, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, + 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x46, 0x75, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x50, 0x72, + 0x6f, 0x70, 0x6f, 0x73, 0x61, 0x6c, 0x4d, 0x73, 0x67, 0x12, 0x49, 0x0a, 0x12, 0x63, 0x68, 0x61, + 0x6e, 0x6e, 0x65, 0x6c, 0x5f, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x5f, 0x6d, 0x73, 0x67, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x70, 0x65, 0x72, 0x75, 0x6e, 0x77, 0x69, 0x72, + 0x65, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4d, + 0x73, 0x67, 0x52, 0x10, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x55, 0x70, 0x64, 0x61, 0x74, + 0x65, 0x4d, 0x73, 0x67, 0x12, 0x30, 0x0a, 0x07, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x6c, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x70, 0x65, 0x72, 0x75, 0x6e, 0x77, 0x69, 0x72, + 0x65, 0x2e, 0x53, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x07, 0x69, + 0x6e, 0x69, 0x74, 0x69, 0x61, 0x6c, 0x12, 0x30, 0x0a, 0x09, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x5f, + 0x6d, 0x61, 0x70, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x70, 0x65, 0x72, 0x75, + 0x6e, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x4d, 0x61, 0x70, 0x52, 0x08, + 0x69, 0x6e, 0x64, 0x65, 0x78, 0x4d, 0x61, 0x70, 0x22, 0x9e, 0x01, 0x0a, 0x23, 0x56, 0x69, 0x72, + 0x74, 0x75, 0x61, 0x6c, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x53, 0x65, 0x74, 0x74, 0x6c, + 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x50, 0x72, 0x6f, 0x70, 0x6f, 0x73, 0x61, 0x6c, 0x4d, 0x73, 0x67, + 0x12, 0x49, 0x0a, 0x12, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x5f, 0x75, 0x70, 0x64, 0x61, + 0x74, 0x65, 0x5f, 0x6d, 0x73, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x70, + 0x65, 0x72, 0x75, 0x6e, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, + 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4d, 0x73, 0x67, 0x52, 0x10, 0x63, 0x68, 0x61, 0x6e, 0x6e, + 0x65, 0x6c, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4d, 0x73, 0x67, 0x12, 0x2c, 0x0a, 0x05, 0x66, + 0x69, 0x6e, 0x61, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x70, 0x65, 0x72, + 0x75, 0x6e, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x53, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x53, 0x74, 0x61, + 0x74, 0x65, 0x52, 0x05, 0x66, 0x69, 0x6e, 0x61, 0x6c, 0x22, 0x60, 0x0a, 0x13, 0x43, 0x68, 0x61, + 0x6e, 0x6e, 0x65, 0x6c, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x41, 0x63, 0x63, 0x4d, 0x73, 0x67, + 0x12, 0x1d, 0x0a, 0x0a, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x5f, 0x69, 0x64, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x49, 0x64, 0x12, + 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, + 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x10, 0x0a, 0x03, 0x73, 0x69, 0x67, + 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x03, 0x73, 0x69, 0x67, 0x22, 0x66, 0x0a, 0x13, 0x43, + 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x6a, 0x4d, 0x73, 0x67, 0x12, 0x1d, 0x0a, 0x0a, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x49, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x04, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x10, 0x0a, 0x03, 0x73, - 0x69, 0x67, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x03, 0x73, 0x69, 0x67, 0x22, 0x66, 0x0a, - 0x13, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, - 0x6a, 0x4d, 0x73, 0x67, 0x12, 0x1d, 0x0a, 0x0a, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x5f, - 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, - 0x6c, 0x49, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x04, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x16, 0x0a, - 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x72, - 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x22, 0x5d, 0x0a, 0x0e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, - 0x53, 0x79, 0x6e, 0x63, 0x4d, 0x73, 0x67, 0x12, 0x14, 0x0a, 0x05, 0x70, 0x68, 0x61, 0x73, 0x65, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, 0x70, 0x68, 0x61, 0x73, 0x65, 0x12, 0x35, 0x0a, - 0x0a, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x5f, 0x74, 0x78, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x16, 0x2e, 0x70, 0x65, 0x72, 0x75, 0x6e, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x54, 0x72, - 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x09, 0x63, 0x75, 0x72, 0x72, 0x65, - 0x6e, 0x74, 0x54, 0x78, 0x42, 0x0d, 0x5a, 0x0b, 0x2e, 0x2e, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x62, 0x75, 0x66, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x28, 0x04, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x16, 0x0a, 0x06, 0x72, + 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x72, 0x65, 0x61, + 0x73, 0x6f, 0x6e, 0x22, 0x5d, 0x0a, 0x0e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x53, 0x79, + 0x6e, 0x63, 0x4d, 0x73, 0x67, 0x12, 0x14, 0x0a, 0x05, 0x70, 0x68, 0x61, 0x73, 0x65, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, 0x70, 0x68, 0x61, 0x73, 0x65, 0x12, 0x35, 0x0a, 0x0a, 0x63, + 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x5f, 0x74, 0x78, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x16, 0x2e, 0x70, 0x65, 0x72, 0x75, 0x6e, 0x77, 0x69, 0x72, 0x65, 0x2e, 0x54, 0x72, 0x61, 0x6e, + 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x09, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, + 0x54, 0x78, 0x42, 0x26, 0x5a, 0x24, 0x70, 0x65, 0x72, 0x75, 0x6e, 0x2e, 0x6e, 0x65, 0x74, 0x77, + 0x6f, 0x72, 0x6b, 0x2f, 0x67, 0x6f, 0x2d, 0x70, 0x65, 0x72, 0x75, 0x6e, 0x2f, 0x77, 0x69, 0x72, + 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x33, } var ( diff --git a/wire/protobuf/wire.proto b/wire/protobuf/wire.proto index b5bd68052..dec4edbcb 100644 --- a/wire/protobuf/wire.proto +++ b/wire/protobuf/wire.proto @@ -156,6 +156,8 @@ message ShutdownMsg { // AuthResponseMsg represents wire.AuthResponseMsg. message AuthResponseMsg { + bytes signature = 1; + } // LedgerChannelProposalMsg represents client.LedgerChannelProposalMsg. diff --git a/wire/test/address.go b/wire/test/address.go index ce1ac570a..6df58e200 100644 --- a/wire/test/address.go +++ b/wire/test/address.go @@ -27,6 +27,7 @@ import ( // TestAddressImplementation runs a test suite designed to test the general // functionality of an address implementation. +// //nolint:revive // The function name `test.Test...` stutters, but it is OK in this special case. func TestAddressImplementation(t *testing.T, newAddress wire.NewAddressFunc, newRandomAddress NewRandomAddressFunc) { rng := pkgtest.Prng(t) diff --git a/wire/test/msgstest.go b/wire/test/msgstest.go index 814bdb7e6..5d876097a 100644 --- a/wire/test/msgstest.go +++ b/wire/test/msgstest.go @@ -40,7 +40,11 @@ func AuthMsgsSerializationTest(t *testing.T, serializerTest func(t *testing.T, m t.Helper() rng := pkgtest.Prng(t) - serializerTest(t, wire.NewAuthResponseMsg(NewRandomAccount(rng))) + testMsg, err := wire.NewAuthResponseMsg(NewRandomAccount(rng)) + if err != nil { + t.Fatal(err) + } + serializerTest(t, testMsg) } // newRandomASCIIString returns a random ascii string of length between minLen and