From c71500d27dfdcc481efe5ce11ade8e5a48eb3557 Mon Sep 17 00:00:00 2001 From: Anatol Lupacescu Date: Tue, 4 May 2021 18:04:39 +0300 Subject: [PATCH 01/12] Draft: validate address against spoofing --- .../libp2p/internal/handshake/handshake.go | 19 ++++ .../internal/handshake/pb/handshake.pb.go | 93 +++++++++++++++---- .../internal/handshake/pb/handshake.proto | 1 + 3 files changed, 93 insertions(+), 20 deletions(-) diff --git a/pkg/p2p/libp2p/internal/handshake/handshake.go b/pkg/p2p/libp2p/internal/handshake/handshake.go index 1ac2fc6b0b6..dcfeb0d7de6 100644 --- a/pkg/p2p/libp2p/internal/handshake/handshake.go +++ b/pkg/p2p/libp2p/internal/handshake/handshake.go @@ -12,6 +12,8 @@ import ( "sync/atomic" "time" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" "github.com/ethersphere/bee/pkg/bzz" "github.com/ethersphere/bee/pkg/crypto" "github.com/ethersphere/bee/pkg/logging" @@ -59,10 +61,15 @@ type AdvertisableAddressResolver interface { Resolve(observedAdddress ma.Multiaddr) (ma.Multiaddr, error) } +type swapBackend interface { + TransactionReceipt(ctx context.Context, txHash common.Hash) (*types.Receipt, error) +} + // Service can perform initiate or handle a handshake between peers. type Service struct { signer crypto.Signer advertisableAddresser AdvertisableAddressResolver + swapBackend swapBackend overlay swarm.Address fullNode bool networkID uint64 @@ -271,6 +278,18 @@ func (s *Service) Handle(ctx context.Context, stream p2p.Stream, remoteMultiaddr s.logger.Infof("greeting \"%s\" from peer: %s", ack.WelcomeMessage, remoteBzzAddress.Overlay.String()) } + incomingTx := common.HexToHash(ack.Transaction) + + rcpt, err := s.swapBackend.TransactionReceipt(context.Background(), incomingTx) + if err != nil { + return nil, fmt.Errorf("get transaction receipt: %w", err) + } + + expectedRemoteBzzAddress := crypto.NewOverlayFromEthereumAddress(rcpt.ContractAddress.Bytes(), s.networkID) + if !expectedRemoteBzzAddress.Equal(remoteBzzAddress.Overlay) { + return nil, fmt.Errorf("given address is spoofed: %v", remoteBzzAddress.Overlay) + } + return &Info{ BzzAddress: remoteBzzAddress, FullNode: ack.FullNode, diff --git a/pkg/p2p/libp2p/internal/handshake/pb/handshake.pb.go b/pkg/p2p/libp2p/internal/handshake/pb/handshake.pb.go index c4693bea55b..bfc434ab1e2 100644 --- a/pkg/p2p/libp2p/internal/handshake/pb/handshake.pb.go +++ b/pkg/p2p/libp2p/internal/handshake/pb/handshake.pb.go @@ -70,6 +70,7 @@ type Ack struct { Address *BzzAddress `protobuf:"bytes,1,opt,name=Address,proto3" json:"Address,omitempty"` NetworkID uint64 `protobuf:"varint,2,opt,name=NetworkID,proto3" json:"NetworkID,omitempty"` FullNode bool `protobuf:"varint,3,opt,name=FullNode,proto3" json:"FullNode,omitempty"` + Transaction string `protobuf:"bytes,4,opt,name=Transaction,proto3" json:"Transaction,omitempty"` WelcomeMessage string `protobuf:"bytes,99,opt,name=WelcomeMessage,proto3" json:"WelcomeMessage,omitempty"` } @@ -127,6 +128,13 @@ func (m *Ack) GetFullNode() bool { return false } +func (m *Ack) GetTransaction() string { + if m != nil { + return m.Transaction + } + return "" +} + func (m *Ack) GetWelcomeMessage() string { if m != nil { return m.WelcomeMessage @@ -256,26 +264,28 @@ func init() { func init() { proto.RegisterFile("handshake.proto", fileDescriptor_a77305914d5d202f) } var fileDescriptor_a77305914d5d202f = []byte{ - // 303 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0xe2, 0xcf, 0x48, 0xcc, 0x4b, - 0x29, 0xce, 0x48, 0xcc, 0x4e, 0xd5, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0xe2, 0x84, 0x0b, 0x28, - 0x19, 0x72, 0x31, 0x07, 0x57, 0xe6, 0x09, 0x69, 0x71, 0x09, 0xf8, 0x27, 0x15, 0xa7, 0x16, 0x95, - 0xa5, 0xa6, 0x84, 0xe6, 0xa5, 0xa4, 0x16, 0xe5, 0x24, 0x56, 0x4a, 0x30, 0x2a, 0x30, 0x6a, 0xf0, - 0x04, 0x61, 0x88, 0x2b, 0xcd, 0x60, 0xe4, 0x62, 0x76, 0x4c, 0xce, 0x16, 0xd2, 0xe7, 0x62, 0x77, - 0x4c, 0x49, 0x29, 0x4a, 0x2d, 0x2e, 0x06, 0x2b, 0xe5, 0x36, 0x12, 0xd5, 0x43, 0x58, 0xe4, 0x54, - 0x55, 0x05, 0x95, 0x0c, 0x82, 0xa9, 0x12, 0x92, 0xe1, 0xe2, 0xf4, 0x4b, 0x2d, 0x29, 0xcf, 0x2f, - 0xca, 0xf6, 0x74, 0x91, 0x60, 0x52, 0x60, 0xd4, 0x60, 0x09, 0x42, 0x08, 0x08, 0x49, 0x71, 0x71, - 0xb8, 0x95, 0xe6, 0xe4, 0xf8, 0xe5, 0xa7, 0xa4, 0x4a, 0x30, 0x2b, 0x30, 0x6a, 0x70, 0x04, 0xc1, - 0xf9, 0x42, 0x6a, 0x5c, 0x7c, 0xe1, 0xa9, 0x39, 0xc9, 0xf9, 0xb9, 0xa9, 0xbe, 0xa9, 0xc5, 0xc5, - 0x89, 0xe9, 0xa9, 0x12, 0xc9, 0x0a, 0x8c, 0x1a, 0x9c, 0x41, 0x68, 0xa2, 0x4a, 0x3e, 0x5c, 0x6c, - 0xc1, 0x95, 0x79, 0x20, 0xc7, 0x29, 0x80, 0xfd, 0x05, 0x75, 0x18, 0x1f, 0x92, 0xc3, 0x82, 0x2b, - 0xf3, 0x82, 0xc0, 0x5e, 0x56, 0x00, 0xfb, 0x02, 0xec, 0x0e, 0x54, 0x15, 0x8e, 0xc9, 0xd9, 0x41, - 0x20, 0x29, 0xa5, 0x04, 0x2e, 0x2e, 0x84, 0x37, 0x40, 0xee, 0x43, 0x0b, 0x1a, 0x38, 0x1f, 0xe4, - 0xb3, 0xe0, 0xcc, 0xf4, 0xbc, 0xc4, 0x92, 0xd2, 0xa2, 0x54, 0xb0, 0x89, 0x3c, 0x41, 0x08, 0x01, - 0x21, 0x09, 0x2e, 0x76, 0xff, 0x32, 0x88, 0x46, 0x66, 0xb0, 0x1c, 0x8c, 0xeb, 0x24, 0x73, 0xe2, - 0x91, 0x1c, 0xe3, 0x85, 0x47, 0x72, 0x8c, 0x0f, 0x1e, 0xc9, 0x31, 0x4e, 0x78, 0x2c, 0xc7, 0x70, - 0xe1, 0xb1, 0x1c, 0xc3, 0x8d, 0xc7, 0x72, 0x0c, 0x51, 0x4c, 0x05, 0x49, 0x49, 0x6c, 0xe0, 0xd8, - 0x32, 0x06, 0x04, 0x00, 0x00, 0xff, 0xff, 0x30, 0x28, 0x02, 0x6f, 0xc0, 0x01, 0x00, 0x00, + // 323 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x64, 0x91, 0xdf, 0x4a, 0xf3, 0x30, + 0x18, 0xc6, 0x97, 0x75, 0xec, 0xcf, 0xbb, 0xb1, 0xef, 0x23, 0x20, 0x14, 0x19, 0x25, 0xf4, 0x40, + 0x8a, 0x07, 0x13, 0xf5, 0x0a, 0x36, 0x44, 0x10, 0x74, 0x83, 0x54, 0x11, 0x3c, 0x32, 0x6b, 0xc3, + 0x36, 0x5a, 0x93, 0x91, 0x74, 0x93, 0xee, 0x2a, 0xbc, 0x1e, 0xaf, 0xc0, 0xc3, 0x1d, 0x7a, 0x28, + 0xdb, 0x8d, 0x48, 0xe3, 0xd6, 0xce, 0x79, 0xf8, 0xfe, 0x9e, 0x27, 0xc9, 0xf3, 0xbc, 0x81, 0x7f, + 0x13, 0x26, 0x42, 0x3d, 0x61, 0x11, 0xef, 0xce, 0x94, 0x4c, 0x24, 0x6e, 0xe4, 0xc0, 0x3d, 0x07, + 0xcb, 0x4f, 0x05, 0x3e, 0x85, 0xff, 0xc3, 0x91, 0xe6, 0x6a, 0xc1, 0xc3, 0x07, 0x11, 0x72, 0x15, + 0xb3, 0xd4, 0x46, 0x04, 0x79, 0x2d, 0xfa, 0x87, 0xbb, 0xef, 0x08, 0xac, 0x5e, 0x10, 0xe1, 0x33, + 0xa8, 0xf5, 0xc2, 0x50, 0x71, 0xad, 0x8d, 0xb5, 0x79, 0x71, 0xd4, 0x2d, 0x1e, 0xea, 0x2f, 0x97, + 0x5b, 0x91, 0xee, 0x5c, 0xb8, 0x03, 0x8d, 0x01, 0x4f, 0x5e, 0xa5, 0x8a, 0x6e, 0xae, 0xec, 0x32, + 0x41, 0x5e, 0x85, 0x16, 0x00, 0x1f, 0x43, 0xfd, 0x7a, 0x1e, 0xc7, 0x03, 0x19, 0x72, 0xdb, 0x22, + 0xc8, 0xab, 0xd3, 0x7c, 0xc6, 0x04, 0x9a, 0xf7, 0x8a, 0x09, 0xcd, 0x82, 0x64, 0x2a, 0x85, 0x5d, + 0x21, 0xc8, 0x6b, 0xd0, 0x7d, 0x84, 0x4f, 0xa0, 0xfd, 0xc8, 0xe3, 0x40, 0xbe, 0xf0, 0x3b, 0xae, + 0x35, 0x1b, 0x73, 0x3b, 0x30, 0xa6, 0x03, 0xea, 0xde, 0x42, 0xd5, 0x4f, 0x45, 0x16, 0x9f, 0x98, + 0xe6, 0xdb, 0xe8, 0xed, 0xbd, 0xe8, 0x7e, 0x2a, 0xa8, 0x59, 0x0a, 0x31, 0x3d, 0x4d, 0xd2, 0xdf, + 0x8e, 0x5e, 0x10, 0xd1, 0x4c, 0x72, 0x9f, 0x01, 0x8a, 0xa2, 0x59, 0x83, 0x83, 0xe5, 0xe5, 0x73, + 0xd6, 0xdd, 0x9f, 0x8e, 0x05, 0x4b, 0xe6, 0x8a, 0x9b, 0x1b, 0x5b, 0xb4, 0x00, 0xd8, 0x86, 0xda, + 0x70, 0xf1, 0x73, 0xd0, 0x32, 0xda, 0x6e, 0xec, 0x77, 0x3e, 0xd6, 0x0e, 0x5a, 0xad, 0x1d, 0xf4, + 0xb5, 0x76, 0xd0, 0xdb, 0xc6, 0x29, 0xad, 0x36, 0x4e, 0xe9, 0x73, 0xe3, 0x94, 0x9e, 0xca, 0xb3, + 0xd1, 0xa8, 0x6a, 0xfe, 0xf3, 0xf2, 0x3b, 0x00, 0x00, 0xff, 0xff, 0xaf, 0x17, 0xf9, 0xa4, 0xe2, + 0x01, 0x00, 0x00, } func (m *Syn) Marshal() (dAtA []byte, err error) { @@ -337,6 +347,13 @@ func (m *Ack) MarshalToSizedBuffer(dAtA []byte) (int, error) { i-- dAtA[i] = 0x9a } + if len(m.Transaction) > 0 { + i -= len(m.Transaction) + copy(dAtA[i:], m.Transaction) + i = encodeVarintHandshake(dAtA, i, uint64(len(m.Transaction))) + i-- + dAtA[i] = 0x22 + } if m.FullNode { i-- if m.FullNode { @@ -498,6 +515,10 @@ func (m *Ack) Size() (n int) { if m.FullNode { n += 2 } + l = len(m.Transaction) + if l > 0 { + n += 1 + l + sovHandshake(uint64(l)) + } l = len(m.WelcomeMessage) if l > 0 { n += 2 + l + sovHandshake(uint64(l)) @@ -740,6 +761,38 @@ func (m *Ack) Unmarshal(dAtA []byte) error { } } m.FullNode = bool(v != 0) + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Transaction", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowHandshake + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthHandshake + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthHandshake + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Transaction = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex case 99: if wireType != 2 { return fmt.Errorf("proto: wrong wireType = %d for field WelcomeMessage", wireType) diff --git a/pkg/p2p/libp2p/internal/handshake/pb/handshake.proto b/pkg/p2p/libp2p/internal/handshake/pb/handshake.proto index 5fd36998d47..4a5c6a9c365 100644 --- a/pkg/p2p/libp2p/internal/handshake/pb/handshake.proto +++ b/pkg/p2p/libp2p/internal/handshake/pb/handshake.proto @@ -16,6 +16,7 @@ message Ack { BzzAddress Address = 1; uint64 NetworkID = 2; bool FullNode = 3; + string Transaction = 4; string WelcomeMessage = 99; } From e4f32320b39a23dcef189c572e5d7ce5cbd5e52d Mon Sep 17 00:00:00 2001 From: Anatol Lupacescu Date: Wed, 5 May 2021 16:21:02 +0300 Subject: [PATCH 02/12] add global swap backend container --- cmd/bee/cmd/cmd.go | 1 + cmd/bee/cmd/start.go | 1 + pkg/node/node.go | 4 +- .../libp2p/internal/handshake/handshake.go | 17 +++++--- .../internal/handshake/handshake_test.go | 39 ++++++++++++++----- pkg/p2p/libp2p/libp2p.go | 5 ++- pkg/p2p/libp2p/libp2p_test.go | 28 ++++++++++++- 7 files changed, 75 insertions(+), 20 deletions(-) diff --git a/cmd/bee/cmd/cmd.go b/cmd/bee/cmd/cmd.go index 950181e7b13..9b5d93bc7b8 100644 --- a/cmd/bee/cmd/cmd.go +++ b/cmd/bee/cmd/cmd.go @@ -58,6 +58,7 @@ const ( optionNameSwapFactoryAddress = "swap-factory-address" optionNameSwapInitialDeposit = "swap-initial-deposit" optionNameSwapEnable = "swap-enable" + optionNameTransaction = "transaction" optionNameFullNode = "full-node" optionNamePostageContractAddress = "postage-stamp-address" optionNamePriceOracleAddress = "price-oracle-address" diff --git a/cmd/bee/cmd/start.go b/cmd/bee/cmd/start.go index 696bc46f16d..18517a01cb0 100644 --- a/cmd/bee/cmd/start.go +++ b/cmd/bee/cmd/start.go @@ -148,6 +148,7 @@ Welcome to the Swarm.... Bzzz Bzzzz Bzzzz SwapInitialDeposit: c.config.GetString(optionNameSwapInitialDeposit), SwapEnable: c.config.GetBool(optionNameSwapEnable), FullNodeMode: fullNode, + Transaction: c.config.GetString(optionNameTransaction), PostageContractAddress: c.config.GetString(optionNamePostageContractAddress), PriceOracleAddress: c.config.GetString(optionNamePriceOracleAddress), }) diff --git a/pkg/node/node.go b/pkg/node/node.go index 19becf56e74..4d30ba9f6fd 100644 --- a/pkg/node/node.go +++ b/pkg/node/node.go @@ -127,6 +127,7 @@ type Options struct { SwapInitialDeposit string SwapEnable bool FullNodeMode bool + Transaction string PostageContractAddress string PriceOracleAddress string } @@ -273,7 +274,7 @@ func NewBee(addr string, swarmAddress swarm.Address, publicKey ecdsa.PublicKey, lightNodes := lightnode.NewContainer() - p2ps, err := libp2p.New(p2pCtx, signer, networkID, swarmAddress, addr, addressbook, stateStore, lightNodes, logger, tracer, libp2p.Options{ + p2ps, err := libp2p.New(p2pCtx, signer, networkID, swarmAddress, addr, addressbook, stateStore, lightNodes, swapBackend, logger, tracer, libp2p.Options{ PrivateKey: libp2pPrivateKey, NATAddr: o.NATAddr, EnableWS: o.EnableWS, @@ -281,6 +282,7 @@ func NewBee(addr string, swarmAddress swarm.Address, publicKey ecdsa.PublicKey, Standalone: o.Standalone, WelcomeMessage: o.WelcomeMessage, FullNode: o.FullNodeMode, + Transaction: o.Transaction, }) if err != nil { return nil, fmt.Errorf("p2p service: %w", err) diff --git a/pkg/p2p/libp2p/internal/handshake/handshake.go b/pkg/p2p/libp2p/internal/handshake/handshake.go index dcfeb0d7de6..c9e4dbe216d 100644 --- a/pkg/p2p/libp2p/internal/handshake/handshake.go +++ b/pkg/p2p/libp2p/internal/handshake/handshake.go @@ -61,7 +61,7 @@ type AdvertisableAddressResolver interface { Resolve(observedAdddress ma.Multiaddr) (ma.Multiaddr, error) } -type swapBackend interface { +type SwapBackend interface { TransactionReceipt(ctx context.Context, txHash common.Hash) (*types.Receipt, error) } @@ -69,9 +69,10 @@ type swapBackend interface { type Service struct { signer crypto.Signer advertisableAddresser AdvertisableAddressResolver - swapBackend swapBackend + swapBackend SwapBackend overlay swarm.Address fullNode bool + transaction string networkID uint64 welcomeMessage atomic.Value receivedHandshakes map[libp2ppeer.ID]struct{} @@ -96,7 +97,7 @@ func (i *Info) LightString() string { } // New creates a new handshake Service. -func New(signer crypto.Signer, advertisableAddresser AdvertisableAddressResolver, overlay swarm.Address, networkID uint64, fullNode bool, welcomeMessage string, logger logging.Logger) (*Service, error) { +func New(signer crypto.Signer, advertisableAddresser AdvertisableAddressResolver, swapBackend SwapBackend, overlay swarm.Address, networkID uint64, fullNode bool, transaction string, welcomeMessage string, logger logging.Logger) (*Service, error) { if len(welcomeMessage) > MaxWelcomeMessageLength { return nil, ErrWelcomeMessageLength } @@ -107,6 +108,8 @@ func New(signer crypto.Signer, advertisableAddresser AdvertisableAddressResolver overlay: overlay, networkID: networkID, fullNode: fullNode, + transaction: transaction, + swapBackend: swapBackend, receivedHandshakes: make(map[libp2ppeer.ID]struct{}), logger: logger, Notifiee: new(network.NoopNotifiee), @@ -178,6 +181,7 @@ func (s *Service) Handshake(ctx context.Context, stream p2p.Stream, peerMultiadd }, NetworkID: s.networkID, FullNode: s.fullNode, + Transaction: s.transaction, WelcomeMessage: welcomeMessage, }); err != nil { return nil, fmt.Errorf("write ack message: %w", err) @@ -257,6 +261,7 @@ func (s *Service) Handle(ctx context.Context, stream p2p.Stream, remoteMultiaddr }, NetworkID: s.networkID, FullNode: s.fullNode, + Transaction: s.transaction, WelcomeMessage: welcomeMessage, }, }); err != nil { @@ -280,14 +285,14 @@ func (s *Service) Handle(ctx context.Context, stream p2p.Stream, remoteMultiaddr incomingTx := common.HexToHash(ack.Transaction) - rcpt, err := s.swapBackend.TransactionReceipt(context.Background(), incomingTx) + txReceipt, err := s.swapBackend.TransactionReceipt(ctx, incomingTx) if err != nil { return nil, fmt.Errorf("get transaction receipt: %w", err) } - expectedRemoteBzzAddress := crypto.NewOverlayFromEthereumAddress(rcpt.ContractAddress.Bytes(), s.networkID) + expectedRemoteBzzAddress := crypto.NewOverlayFromEthereumAddress(txReceipt.ContractAddress.Bytes(), s.networkID) if !expectedRemoteBzzAddress.Equal(remoteBzzAddress.Overlay) { - return nil, fmt.Errorf("given address is spoofed: %v", remoteBzzAddress.Overlay) + return nil, fmt.Errorf("given address is not registered on Ethereum: %v", remoteBzzAddress.Overlay) } return &Info{ diff --git a/pkg/p2p/libp2p/internal/handshake/handshake_test.go b/pkg/p2p/libp2p/internal/handshake/handshake_test.go index 499a1eccf8c..95c67d6a8ad 100644 --- a/pkg/p2p/libp2p/internal/handshake/handshake_test.go +++ b/pkg/p2p/libp2p/internal/handshake/handshake_test.go @@ -12,6 +12,8 @@ import ( "io/ioutil" "testing" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" "github.com/ethersphere/bee/pkg/bzz" "github.com/ethersphere/bee/pkg/crypto" "github.com/ethersphere/bee/pkg/logging" @@ -92,7 +94,12 @@ func TestHandshake(t *testing.T) { aaddresser := &AdvertisableAddresserMock{} - handshakeService, err := handshake.New(signer1, aaddresser, node1Info.BzzAddress.Overlay, networkID, true, testWelcomeMessage, logger) + ethAddr, _ := signer2.EthereumAddress() + swapBackend := &swapBackendMock{ + contractAddr: ethAddr, + } + + handshakeService, err := handshake.New(signer1, aaddresser, swapBackend, node1Info.BzzAddress.Overlay, networkID, true, "", testWelcomeMessage, logger) if err != nil { t.Fatal(err) } @@ -160,7 +167,7 @@ func TestHandshake(t *testing.T) { const LongMessage = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi consectetur urna ut lorem sollicitudin posuere. Donec sagittis laoreet sapien." expectedErr := handshake.ErrWelcomeMessageLength - _, err := handshake.New(signer1, aaddresser, node1Info.BzzAddress.Overlay, networkID, true, LongMessage, logger) + _, err := handshake.New(signer1, aaddresser, swapBackend, node1Info.BzzAddress.Overlay, networkID, true, "", LongMessage, logger) if err == nil || err.Error() != expectedErr.Error() { t.Fatal("expected:", expectedErr, "got:", err) } @@ -368,7 +375,7 @@ func TestHandshake(t *testing.T) { }) t.Run("Handle - OK", func(t *testing.T) { - handshakeService, err := handshake.New(signer1, aaddresser, node1Info.BzzAddress.Overlay, networkID, true, "", logger) + handshakeService, err := handshake.New(signer1, aaddresser, swapBackend, node1Info.BzzAddress.Overlay, networkID, true, "", "", logger) if err != nil { t.Fatal(err) } @@ -425,7 +432,7 @@ func TestHandshake(t *testing.T) { }) t.Run("Handle - read error ", func(t *testing.T) { - handshakeService, err := handshake.New(signer1, aaddresser, node1Info.BzzAddress.Overlay, networkID, true, "", logger) + handshakeService, err := handshake.New(signer1, aaddresser, swapBackend, node1Info.BzzAddress.Overlay, networkID, true, "", "", logger) if err != nil { t.Fatal(err) } @@ -444,7 +451,7 @@ func TestHandshake(t *testing.T) { }) t.Run("Handle - write error ", func(t *testing.T) { - handshakeService, err := handshake.New(signer1, aaddresser, node1Info.BzzAddress.Overlay, networkID, true, "", logger) + handshakeService, err := handshake.New(signer1, aaddresser, swapBackend, node1Info.BzzAddress.Overlay, networkID, true, "", "", logger) if err != nil { t.Fatal(err) } @@ -471,7 +478,7 @@ func TestHandshake(t *testing.T) { }) t.Run("Handle - ack read error ", func(t *testing.T) { - handshakeService, err := handshake.New(signer1, aaddresser, node1Info.BzzAddress.Overlay, networkID, true, "", logger) + handshakeService, err := handshake.New(signer1, aaddresser, swapBackend, node1Info.BzzAddress.Overlay, networkID, true, "", "", logger) if err != nil { t.Fatal(err) } @@ -500,7 +507,7 @@ func TestHandshake(t *testing.T) { }) t.Run("Handle - networkID mismatch ", func(t *testing.T) { - handshakeService, err := handshake.New(signer1, aaddresser, node1Info.BzzAddress.Overlay, networkID, true, "", logger) + handshakeService, err := handshake.New(signer1, aaddresser, swapBackend, node1Info.BzzAddress.Overlay, networkID, true, "", "", logger) if err != nil { t.Fatal(err) } @@ -539,7 +546,7 @@ func TestHandshake(t *testing.T) { }) t.Run("Handle - duplicate handshake", func(t *testing.T) { - handshakeService, err := handshake.New(signer1, aaddresser, node1Info.BzzAddress.Overlay, networkID, true, "", logger) + handshakeService, err := handshake.New(signer1, aaddresser, swapBackend, node1Info.BzzAddress.Overlay, networkID, true, "", "", logger) if err != nil { t.Fatal(err) } @@ -601,7 +608,7 @@ func TestHandshake(t *testing.T) { }) t.Run("Handle - invalid ack", func(t *testing.T) { - handshakeService, err := handshake.New(signer1, aaddresser, node1Info.BzzAddress.Overlay, networkID, true, "", logger) + handshakeService, err := handshake.New(signer1, aaddresser, swapBackend, node1Info.BzzAddress.Overlay, networkID, true, "", "", logger) if err != nil { t.Fatal(err) } @@ -635,8 +642,10 @@ func TestHandshake(t *testing.T) { } }) + //TODO add bad case scenario + t.Run("Handle - advertisable error", func(t *testing.T) { - handshakeService, err := handshake.New(signer1, aaddresser, node1Info.BzzAddress.Overlay, networkID, true, "", logger) + handshakeService, err := handshake.New(signer1, aaddresser, swapBackend, node1Info.BzzAddress.Overlay, networkID, true, "", "", logger) if err != nil { t.Fatal(err) } @@ -693,3 +702,13 @@ func (a *AdvertisableAddresserMock) Resolve(observedAdddress ma.Multiaddr) (ma.M return observedAdddress, nil } + +type swapBackendMock struct { + contractAddr common.Address +} + +func (s *swapBackendMock) TransactionReceipt(context.Context, common.Hash) (*types.Receipt, error) { + return &types.Receipt{ + ContractAddress: s.contractAddr, + }, nil +} diff --git a/pkg/p2p/libp2p/libp2p.go b/pkg/p2p/libp2p/libp2p.go index b33a67c57c8..3b10a8ce36f 100644 --- a/pkg/p2p/libp2p/libp2p.go +++ b/pkg/p2p/libp2p/libp2p.go @@ -84,9 +84,10 @@ type Options struct { Standalone bool FullNode bool WelcomeMessage string + Transaction string } -func New(ctx context.Context, signer beecrypto.Signer, networkID uint64, overlay swarm.Address, addr string, ab addressbook.Putter, storer storage.StateStorer, lightNodes *lightnode.Container, logger logging.Logger, tracer *tracing.Tracer, o Options) (*Service, error) { +func New(ctx context.Context, signer beecrypto.Signer, networkID uint64, overlay swarm.Address, addr string, ab addressbook.Putter, storer storage.StateStorer, lightNodes *lightnode.Container, swapBackend handshake.SwapBackend, logger logging.Logger, tracer *tracing.Tracer, o Options) (*Service, error) { host, port, err := net.SplitHostPort(addr) if err != nil { return nil, fmt.Errorf("address: %w", err) @@ -209,7 +210,7 @@ func New(ctx context.Context, signer beecrypto.Signer, networkID uint64, overlay advertisableAddresser = natAddrResolver } - handshakeService, err := handshake.New(signer, advertisableAddresser, overlay, networkID, o.FullNode, o.WelcomeMessage, logger) + handshakeService, err := handshake.New(signer, advertisableAddresser, swapBackend, overlay, networkID, o.FullNode, o.Transaction, o.WelcomeMessage, logger) if err != nil { return nil, fmt.Errorf("handshake service: %w", err) } diff --git a/pkg/p2p/libp2p/libp2p_test.go b/pkg/p2p/libp2p/libp2p_test.go index defd056c8df..d07626384a4 100644 --- a/pkg/p2p/libp2p/libp2p_test.go +++ b/pkg/p2p/libp2p/libp2p_test.go @@ -13,6 +13,9 @@ import ( "testing" "time" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/ethereum/go-ethereum/core/types" "github.com/ethersphere/bee/pkg/addressbook" "github.com/ethersphere/bee/pkg/crypto" "github.com/ethersphere/bee/pkg/logging" @@ -28,9 +31,15 @@ type libp2pServiceOpts struct { Logger logging.Logger Addressbook addressbook.Interface PrivateKey *ecdsa.PrivateKey + MockPeerKey *ecdsa.PrivateKey libp2pOpts libp2p.Options } +// SwapBackend maps overlay to eth address +type SwapBackend map[common.Hash]common.Address + +var MockSwapBackend = make(SwapBackend) + // newService constructs a new libp2p service. func newService(t *testing.T, networkID uint64, o libp2pServiceOpts) (s *libp2p.Service, overlay swarm.Address) { t.Helper() @@ -69,7 +78,15 @@ func newService(t *testing.T, networkID uint64, o libp2pServiceOpts) (s *libp2p. lightnodes := lightnode.NewContainer() - s, err = libp2p.New(ctx, crypto.NewDefaultSigner(swarmKey), networkID, overlay, addr, o.Addressbook, statestore, lightnodes, o.Logger, nil, o.libp2pOpts) + opts := o.libp2pOpts + opts.Transaction = hexutil.EncodeUint64(o.PrivateKey.Y.Uint64()) + + signer := crypto.NewDefaultSigner(swarmKey) + ethAddr, _ := signer.EthereumAddress() + tx := common.HexToHash(opts.Transaction) + MockSwapBackend[tx] = ethAddr + + s, err = libp2p.New(ctx, signer, networkID, overlay, addr, o.Addressbook, statestore, lightnodes, new(swapBackendMock), o.Logger, nil, opts) if err != nil { t.Fatal(err) } @@ -78,6 +95,7 @@ func newService(t *testing.T, networkID uint64, o libp2pServiceOpts) (s *libp2p. t.Cleanup(func() { cancel() s.Close() + delete(MockSwapBackend, tx) }) return s, overlay } @@ -150,3 +168,11 @@ func serviceUnderlayAddress(t *testing.T, s *libp2p.Service) multiaddr.Multiaddr } return addrs[0] } + +type swapBackendMock struct{} + +func (s *swapBackendMock) TransactionReceipt(ctx context.Context, txHash common.Hash) (*types.Receipt, error) { + return &types.Receipt{ + ContractAddress: MockSwapBackend[txHash], + }, nil +} From f9750de9cfc1c6bc66426d70cfe65b9326aef826 Mon Sep 17 00:00:00 2001 From: Anatol Lupacescu Date: Wed, 5 May 2021 17:41:57 +0300 Subject: [PATCH 03/12] add test for spoofed address --- .../libp2p/internal/handshake/handshake.go | 5 ++- .../internal/handshake/handshake_test.go | 39 ++++++++++++++++++- pkg/p2p/libp2p/libp2p_test.go | 35 ++++++++++++----- 3 files changed, 67 insertions(+), 12 deletions(-) diff --git a/pkg/p2p/libp2p/internal/handshake/handshake.go b/pkg/p2p/libp2p/internal/handshake/handshake.go index c9e4dbe216d..8fe8c1fc184 100644 --- a/pkg/p2p/libp2p/internal/handshake/handshake.go +++ b/pkg/p2p/libp2p/internal/handshake/handshake.go @@ -52,6 +52,9 @@ var ( // ErrInvalidSyn is returned if observable address in ack is not a valid.. ErrInvalidSyn = errors.New("invalid syn") + // ErrAddressNotFound is returned if observable address in ack is not a valid.. + ErrAddressNotFound = errors.New("address not found on blockchain") + // ErrWelcomeMessageLength is returned if the welcome message is longer than the maximum length ErrWelcomeMessageLength = fmt.Errorf("handshake welcome message longer than maximum of %d characters", MaxWelcomeMessageLength) ) @@ -292,7 +295,7 @@ func (s *Service) Handle(ctx context.Context, stream p2p.Stream, remoteMultiaddr expectedRemoteBzzAddress := crypto.NewOverlayFromEthereumAddress(txReceipt.ContractAddress.Bytes(), s.networkID) if !expectedRemoteBzzAddress.Equal(remoteBzzAddress.Overlay) { - return nil, fmt.Errorf("given address is not registered on Ethereum: %v", remoteBzzAddress.Overlay) + return nil, fmt.Errorf("given address is not registered on Ethereum: %v: %w", remoteBzzAddress.Overlay, ErrAddressNotFound) } return &Info{ diff --git a/pkg/p2p/libp2p/internal/handshake/handshake_test.go b/pkg/p2p/libp2p/internal/handshake/handshake_test.go index 95c67d6a8ad..552e6a88fcf 100644 --- a/pkg/p2p/libp2p/internal/handshake/handshake_test.go +++ b/pkg/p2p/libp2p/internal/handshake/handshake_test.go @@ -10,6 +10,7 @@ import ( "errors" "fmt" "io/ioutil" + "math/big" "testing" "github.com/ethereum/go-ethereum/common" @@ -642,7 +643,43 @@ func TestHandshake(t *testing.T) { } }) - //TODO add bad case scenario + t.Run("Handle - transaction is not on the blockchain", func(t *testing.T) { + sbMock := &swapBackendMock{ + contractAddr: common.BigToAddress(big.NewInt(11)), + } + handshakeService, err := handshake.New(signer1, aaddresser, sbMock, node1Info.BzzAddress.Overlay, networkID, true, "0xff", "", logger) + if err != nil { + t.Fatal(err) + } + var buffer1 bytes.Buffer + var buffer2 bytes.Buffer + stream1 := mock.NewStream(&buffer1, &buffer2) + stream2 := mock.NewStream(&buffer2, &buffer1) + + w := protobuf.NewWriter(stream2) + if err := w.WriteMsg(&pb.Syn{ + ObservedUnderlay: node1maBinary, + }); err != nil { + t.Fatal(err) + } + + if err := w.WriteMsg(&pb.Ack{ + Address: &pb.BzzAddress{ + Underlay: node2maBinary, + Overlay: node2BzzAddress.Overlay.Bytes(), + Signature: node2BzzAddress.Signature, + }, + NetworkID: networkID, + FullNode: true, + }); err != nil { + t.Fatal(err) + } + + _, err = handshakeService.Handle(context.Background(), stream1, node2AddrInfo.Addrs[0], node2AddrInfo.ID) + if !errors.Is(err, handshake.ErrAddressNotFound) { + t.Fatalf("expected error %v, got %v", handshake.ErrAddressNotFound, err) + } + }) t.Run("Handle - advertisable error", func(t *testing.T) { handshakeService, err := handshake.New(signer1, aaddresser, swapBackend, node1Info.BzzAddress.Overlay, networkID, true, "", "", logger) diff --git a/pkg/p2p/libp2p/libp2p_test.go b/pkg/p2p/libp2p/libp2p_test.go index d07626384a4..87f84b546a9 100644 --- a/pkg/p2p/libp2p/libp2p_test.go +++ b/pkg/p2p/libp2p/libp2p_test.go @@ -10,6 +10,7 @@ import ( "crypto/ecdsa" "io/ioutil" "sort" + "sync" "testing" "time" @@ -35,10 +36,10 @@ type libp2pServiceOpts struct { libp2pOpts libp2p.Options } -// SwapBackend maps overlay to eth address -type SwapBackend map[common.Hash]common.Address - -var MockSwapBackend = make(SwapBackend) +// mockSwapBackend is used in spoofed address validation +var mockSwapBackend = &SwapBackend{ + addrs: make(map[common.Hash]common.Address), +} // newService constructs a new libp2p service. func newService(t *testing.T, networkID uint64, o libp2pServiceOpts) (s *libp2p.Service, overlay swarm.Address) { @@ -84,9 +85,9 @@ func newService(t *testing.T, networkID uint64, o libp2pServiceOpts) (s *libp2p. signer := crypto.NewDefaultSigner(swarmKey) ethAddr, _ := signer.EthereumAddress() tx := common.HexToHash(opts.Transaction) - MockSwapBackend[tx] = ethAddr + mockSwapBackend.add(tx, ethAddr) - s, err = libp2p.New(ctx, signer, networkID, overlay, addr, o.Addressbook, statestore, lightnodes, new(swapBackendMock), o.Logger, nil, opts) + s, err = libp2p.New(ctx, signer, networkID, overlay, addr, o.Addressbook, statestore, lightnodes, mockSwapBackend, o.Logger, nil, opts) if err != nil { t.Fatal(err) } @@ -95,7 +96,7 @@ func newService(t *testing.T, networkID uint64, o libp2pServiceOpts) (s *libp2p. t.Cleanup(func() { cancel() s.Close() - delete(MockSwapBackend, tx) + delete(mockSwapBackend.addrs, tx) }) return s, overlay } @@ -169,10 +170,24 @@ func serviceUnderlayAddress(t *testing.T, s *libp2p.Service) multiaddr.Multiaddr return addrs[0] } -type swapBackendMock struct{} +// SwapBackend maps overlay to eth address +type SwapBackend struct { + addrs map[common.Hash]common.Address + m sync.RWMutex +} + +func (sb *SwapBackend) add(tx common.Hash, ethAddr common.Address) { + sb.m.Lock() + defer sb.m.Unlock() + + mockSwapBackend.addrs[tx] = ethAddr +} + +func (sb *SwapBackend) TransactionReceipt(ctx context.Context, txHash common.Hash) (*types.Receipt, error) { + mockSwapBackend.m.RLock() + defer mockSwapBackend.m.RUnlock() -func (s *swapBackendMock) TransactionReceipt(ctx context.Context, txHash common.Hash) (*types.Receipt, error) { return &types.Receipt{ - ContractAddress: MockSwapBackend[txHash], + ContractAddress: mockSwapBackend.addrs[txHash], }, nil } From 5d62a1f1da37fd7d5b86fd37f29aa4946e08bf6a Mon Sep 17 00:00:00 2001 From: Anatol Lupacescu Date: Thu, 6 May 2021 11:59:29 +0300 Subject: [PATCH 04/12] get tx hash from statestore if not provided --- cmd/bee/cmd/cmd.go | 1 + pkg/node/node.go | 24 +++++++++++++++++++++++- pkg/settlement/swap/chequebook/init.go | 6 +++--- 3 files changed, 27 insertions(+), 4 deletions(-) diff --git a/cmd/bee/cmd/cmd.go b/cmd/bee/cmd/cmd.go index 9b5d93bc7b8..0ad37dd1aef 100644 --- a/cmd/bee/cmd/cmd.go +++ b/cmd/bee/cmd/cmd.go @@ -231,6 +231,7 @@ func (c *command) setAllFlags(cmd *cobra.Command) { cmd.Flags().Bool(optionNameFullNode, false, "cause the node to start in full mode") cmd.Flags().String(optionNamePostageContractAddress, "", "postage stamp contract address") cmd.Flags().String(optionNamePriceOracleAddress, "", "price oracle address") + cmd.Flags().String(optionNameTransaction, "", "transaction hash") } func newLogger(cmd *cobra.Command, verbosity string) (logging.Logger, error) { diff --git a/pkg/node/node.go b/pkg/node/node.go index 4d30ba9f6fd..6e9ce172147 100644 --- a/pkg/node/node.go +++ b/pkg/node/node.go @@ -274,6 +274,11 @@ func NewBee(addr string, swarmAddress swarm.Address, publicKey ecdsa.PublicKey, lightNodes := lightnode.NewContainer() + txHash, err := getTxHash(stateStore, logger, o.Transaction) + if err != nil { + return nil, err + } + p2ps, err := libp2p.New(p2pCtx, signer, networkID, swarmAddress, addr, addressbook, stateStore, lightNodes, swapBackend, logger, tracer, libp2p.Options{ PrivateKey: libp2pPrivateKey, NATAddr: o.NATAddr, @@ -282,7 +287,7 @@ func NewBee(addr string, swarmAddress swarm.Address, publicKey ecdsa.PublicKey, Standalone: o.Standalone, WelcomeMessage: o.WelcomeMessage, FullNode: o.FullNodeMode, - Transaction: o.Transaction, + Transaction: txHash, }) if err != nil { return nil, fmt.Errorf("p2p service: %w", err) @@ -783,3 +788,20 @@ func (e *multiError) add(err error) { func (e *multiError) hasErrors() bool { return len(e.errors) > 0 } + +func getTxHash(stateStore storage.StateStorer, logger logging.Logger, transaction string) (string, error) { + if len(transaction) == 32 { + logger.Info("using the provided transaction hash") + return transaction, nil + } + + logger.Info("no transaction hash provided, trying to fetch it from the state") + + var txHash common.Hash + key := chequebook.ChequebookDeploymentKey + if err := stateStore.Get(key, &txHash); err != nil { + return "", err + } + + return txHash.String(), nil +} diff --git a/pkg/settlement/swap/chequebook/init.go b/pkg/settlement/swap/chequebook/init.go index f79611f98df..a4057cf2c45 100644 --- a/pkg/settlement/swap/chequebook/init.go +++ b/pkg/settlement/swap/chequebook/init.go @@ -19,7 +19,7 @@ import ( const ( chequebookKey = "swap_chequebook" - chequebookDeploymentKey = "swap_chequebook_transaction_deployment" + ChequebookDeploymentKey = "swap_chequebook_transaction_deployment" balanceCheckBackoffDuration = 20 * time.Second balanceCheckMaxRetries = 10 @@ -124,7 +124,7 @@ func Init( } var txHash common.Hash - err = stateStore.Get(chequebookDeploymentKey, &txHash) + err = stateStore.Get(ChequebookDeploymentKey, &txHash) if err != nil && err != storage.ErrNotFound { return nil, err } @@ -145,7 +145,7 @@ func Init( logger.Infof("deploying new chequebook in transaction %x", txHash) - err = stateStore.Put(chequebookDeploymentKey, txHash) + err = stateStore.Put(ChequebookDeploymentKey, txHash) if err != nil { return nil, err } From fe273cba854fae428a7e468cdb58fcea066eca2d Mon Sep 17 00:00:00 2001 From: Anatol Lupacescu Date: Thu, 6 May 2021 12:18:09 +0300 Subject: [PATCH 05/12] fix race condition --- pkg/p2p/libp2p/libp2p_test.go | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/pkg/p2p/libp2p/libp2p_test.go b/pkg/p2p/libp2p/libp2p_test.go index 87f84b546a9..932a6e643de 100644 --- a/pkg/p2p/libp2p/libp2p_test.go +++ b/pkg/p2p/libp2p/libp2p_test.go @@ -96,7 +96,7 @@ func newService(t *testing.T, networkID uint64, o libp2pServiceOpts) (s *libp2p. t.Cleanup(func() { cancel() s.Close() - delete(mockSwapBackend.addrs, tx) + mockSwapBackend.remove(tx) }) return s, overlay } @@ -180,14 +180,21 @@ func (sb *SwapBackend) add(tx common.Hash, ethAddr common.Address) { sb.m.Lock() defer sb.m.Unlock() - mockSwapBackend.addrs[tx] = ethAddr + sb.addrs[tx] = ethAddr +} + +func (sb *SwapBackend) remove(tx common.Hash) { + sb.m.Lock() + defer sb.m.Unlock() + + delete(sb.addrs, tx) } func (sb *SwapBackend) TransactionReceipt(ctx context.Context, txHash common.Hash) (*types.Receipt, error) { - mockSwapBackend.m.RLock() - defer mockSwapBackend.m.RUnlock() + sb.m.RLock() + defer sb.m.RUnlock() return &types.Receipt{ - ContractAddress: mockSwapBackend.addrs[txHash], + ContractAddress: sb.addrs[txHash], }, nil } From f11136b58d8d0a73781b1178c452a8410fee85d9 Mon Sep 17 00:00:00 2001 From: Anatol Lupacescu Date: Fri, 7 May 2021 13:55:25 +0300 Subject: [PATCH 06/12] change the way we get transaction initiator --- pkg/node/node.go | 4 +- .../libp2p/internal/handshake/handshake.go | 19 ++++---- .../internal/handshake/handshake_test.go | 24 +++------- pkg/p2p/libp2p/libp2p.go | 2 +- pkg/p2p/libp2p/libp2p_test.go | 47 ++----------------- .../swap/transaction/sender_validator.go | 46 ++++++++++++++++++ 6 files changed, 69 insertions(+), 73 deletions(-) create mode 100644 pkg/settlement/swap/transaction/sender_validator.go diff --git a/pkg/node/node.go b/pkg/node/node.go index 6e9ce172147..2af9d890702 100644 --- a/pkg/node/node.go +++ b/pkg/node/node.go @@ -279,7 +279,9 @@ func NewBee(addr string, swarmAddress swarm.Address, publicKey ecdsa.PublicKey, return nil, err } - p2ps, err := libp2p.New(p2pCtx, signer, networkID, swarmAddress, addr, addressbook, stateStore, lightNodes, swapBackend, logger, tracer, libp2p.Options{ + vd := transaction.NewValidator(swapBackend, chainID) + + p2ps, err := libp2p.New(p2pCtx, signer, networkID, swarmAddress, addr, addressbook, stateStore, lightNodes, vd.MatchesSender, logger, tracer, libp2p.Options{ PrivateKey: libp2pPrivateKey, NATAddr: o.NATAddr, EnableWS: o.EnableWS, diff --git a/pkg/p2p/libp2p/internal/handshake/handshake.go b/pkg/p2p/libp2p/internal/handshake/handshake.go index 8fe8c1fc184..b1f8c494fc1 100644 --- a/pkg/p2p/libp2p/internal/handshake/handshake.go +++ b/pkg/p2p/libp2p/internal/handshake/handshake.go @@ -53,7 +53,7 @@ var ( ErrInvalidSyn = errors.New("invalid syn") // ErrAddressNotFound is returned if observable address in ack is not a valid.. - ErrAddressNotFound = errors.New("address not found on blockchain") + ErrAddressNotFound = errors.New("address not found") // ErrWelcomeMessageLength is returned if the welcome message is longer than the maximum length ErrWelcomeMessageLength = fmt.Errorf("handshake welcome message longer than maximum of %d characters", MaxWelcomeMessageLength) @@ -72,7 +72,7 @@ type SwapBackend interface { type Service struct { signer crypto.Signer advertisableAddresser AdvertisableAddressResolver - swapBackend SwapBackend + isSender SenderMatcher overlay swarm.Address fullNode bool transaction string @@ -99,8 +99,10 @@ func (i *Info) LightString() string { return "" } +type SenderMatcher func(context.Context, string, uint64, swarm.Address) (bool, error) + // New creates a new handshake Service. -func New(signer crypto.Signer, advertisableAddresser AdvertisableAddressResolver, swapBackend SwapBackend, overlay swarm.Address, networkID uint64, fullNode bool, transaction string, welcomeMessage string, logger logging.Logger) (*Service, error) { +func New(signer crypto.Signer, advertisableAddresser AdvertisableAddressResolver, isSender SenderMatcher, overlay swarm.Address, networkID uint64, fullNode bool, transaction string, welcomeMessage string, logger logging.Logger) (*Service, error) { if len(welcomeMessage) > MaxWelcomeMessageLength { return nil, ErrWelcomeMessageLength } @@ -112,7 +114,7 @@ func New(signer crypto.Signer, advertisableAddresser AdvertisableAddressResolver networkID: networkID, fullNode: fullNode, transaction: transaction, - swapBackend: swapBackend, + isSender: isSender, receivedHandshakes: make(map[libp2ppeer.ID]struct{}), logger: logger, Notifiee: new(network.NoopNotifiee), @@ -286,15 +288,12 @@ func (s *Service) Handle(ctx context.Context, stream p2p.Stream, remoteMultiaddr s.logger.Infof("greeting \"%s\" from peer: %s", ack.WelcomeMessage, remoteBzzAddress.Overlay.String()) } - incomingTx := common.HexToHash(ack.Transaction) - - txReceipt, err := s.swapBackend.TransactionReceipt(ctx, incomingTx) + matchesSender, err := s.isSender(ctx, ack.Transaction, s.networkID, remoteBzzAddress.Overlay) if err != nil { - return nil, fmt.Errorf("get transaction receipt: %w", err) + return nil, err } - expectedRemoteBzzAddress := crypto.NewOverlayFromEthereumAddress(txReceipt.ContractAddress.Bytes(), s.networkID) - if !expectedRemoteBzzAddress.Equal(remoteBzzAddress.Overlay) { + if !matchesSender { return nil, fmt.Errorf("given address is not registered on Ethereum: %v: %w", remoteBzzAddress.Overlay, ErrAddressNotFound) } diff --git a/pkg/p2p/libp2p/internal/handshake/handshake_test.go b/pkg/p2p/libp2p/internal/handshake/handshake_test.go index 552e6a88fcf..949c27bd3a4 100644 --- a/pkg/p2p/libp2p/internal/handshake/handshake_test.go +++ b/pkg/p2p/libp2p/internal/handshake/handshake_test.go @@ -10,11 +10,8 @@ import ( "errors" "fmt" "io/ioutil" - "math/big" "testing" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/types" "github.com/ethersphere/bee/pkg/bzz" "github.com/ethersphere/bee/pkg/crypto" "github.com/ethersphere/bee/pkg/logging" @@ -22,6 +19,7 @@ import ( "github.com/ethersphere/bee/pkg/p2p/libp2p/internal/handshake/mock" "github.com/ethersphere/bee/pkg/p2p/libp2p/internal/handshake/pb" "github.com/ethersphere/bee/pkg/p2p/protobuf" + "github.com/ethersphere/bee/pkg/swarm" libp2ppeer "github.com/libp2p/go-libp2p-core/peer" ma "github.com/multiformats/go-multiaddr" @@ -95,9 +93,8 @@ func TestHandshake(t *testing.T) { aaddresser := &AdvertisableAddresserMock{} - ethAddr, _ := signer2.EthereumAddress() - swapBackend := &swapBackendMock{ - contractAddr: ethAddr, + swapBackend := func(context.Context, string, uint64, swarm.Address) (bool, error) { + return true, nil } handshakeService, err := handshake.New(signer1, aaddresser, swapBackend, node1Info.BzzAddress.Overlay, networkID, true, "", testWelcomeMessage, logger) @@ -644,9 +641,10 @@ func TestHandshake(t *testing.T) { }) t.Run("Handle - transaction is not on the blockchain", func(t *testing.T) { - sbMock := &swapBackendMock{ - contractAddr: common.BigToAddress(big.NewInt(11)), + sbMock := func(context.Context, string, uint64, swarm.Address) (bool, error) { + return false, nil } + handshakeService, err := handshake.New(signer1, aaddresser, sbMock, node1Info.BzzAddress.Overlay, networkID, true, "0xff", "", logger) if err != nil { t.Fatal(err) @@ -739,13 +737,3 @@ func (a *AdvertisableAddresserMock) Resolve(observedAdddress ma.Multiaddr) (ma.M return observedAdddress, nil } - -type swapBackendMock struct { - contractAddr common.Address -} - -func (s *swapBackendMock) TransactionReceipt(context.Context, common.Hash) (*types.Receipt, error) { - return &types.Receipt{ - ContractAddress: s.contractAddr, - }, nil -} diff --git a/pkg/p2p/libp2p/libp2p.go b/pkg/p2p/libp2p/libp2p.go index 3b10a8ce36f..541d69daf77 100644 --- a/pkg/p2p/libp2p/libp2p.go +++ b/pkg/p2p/libp2p/libp2p.go @@ -87,7 +87,7 @@ type Options struct { Transaction string } -func New(ctx context.Context, signer beecrypto.Signer, networkID uint64, overlay swarm.Address, addr string, ab addressbook.Putter, storer storage.StateStorer, lightNodes *lightnode.Container, swapBackend handshake.SwapBackend, logger logging.Logger, tracer *tracing.Tracer, o Options) (*Service, error) { +func New(ctx context.Context, signer beecrypto.Signer, networkID uint64, overlay swarm.Address, addr string, ab addressbook.Putter, storer storage.StateStorer, lightNodes *lightnode.Container, swapBackend handshake.SenderMatcher, logger logging.Logger, tracer *tracing.Tracer, o Options) (*Service, error) { host, port, err := net.SplitHostPort(addr) if err != nil { return nil, fmt.Errorf("address: %w", err) diff --git a/pkg/p2p/libp2p/libp2p_test.go b/pkg/p2p/libp2p/libp2p_test.go index 932a6e643de..6c839a9fb44 100644 --- a/pkg/p2p/libp2p/libp2p_test.go +++ b/pkg/p2p/libp2p/libp2p_test.go @@ -10,13 +10,10 @@ import ( "crypto/ecdsa" "io/ioutil" "sort" - "sync" "testing" "time" - "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" - "github.com/ethereum/go-ethereum/core/types" "github.com/ethersphere/bee/pkg/addressbook" "github.com/ethersphere/bee/pkg/crypto" "github.com/ethersphere/bee/pkg/logging" @@ -36,11 +33,6 @@ type libp2pServiceOpts struct { libp2pOpts libp2p.Options } -// mockSwapBackend is used in spoofed address validation -var mockSwapBackend = &SwapBackend{ - addrs: make(map[common.Hash]common.Address), -} - // newService constructs a new libp2p service. func newService(t *testing.T, networkID uint64, o libp2pServiceOpts) (s *libp2p.Service, overlay swarm.Address) { t.Helper() @@ -82,12 +74,11 @@ func newService(t *testing.T, networkID uint64, o libp2pServiceOpts) (s *libp2p. opts := o.libp2pOpts opts.Transaction = hexutil.EncodeUint64(o.PrivateKey.Y.Uint64()) - signer := crypto.NewDefaultSigner(swarmKey) - ethAddr, _ := signer.EthereumAddress() - tx := common.HexToHash(opts.Transaction) - mockSwapBackend.add(tx, ethAddr) + senderMatcher := func(context.Context, string, uint64, swarm.Address) (bool, error) { + return true, nil + } - s, err = libp2p.New(ctx, signer, networkID, overlay, addr, o.Addressbook, statestore, lightnodes, mockSwapBackend, o.Logger, nil, opts) + s, err = libp2p.New(ctx, crypto.NewDefaultSigner(swarmKey), networkID, overlay, addr, o.Addressbook, statestore, lightnodes, senderMatcher, o.Logger, nil, opts) if err != nil { t.Fatal(err) } @@ -96,7 +87,6 @@ func newService(t *testing.T, networkID uint64, o libp2pServiceOpts) (s *libp2p. t.Cleanup(func() { cancel() s.Close() - mockSwapBackend.remove(tx) }) return s, overlay } @@ -169,32 +159,3 @@ func serviceUnderlayAddress(t *testing.T, s *libp2p.Service) multiaddr.Multiaddr } return addrs[0] } - -// SwapBackend maps overlay to eth address -type SwapBackend struct { - addrs map[common.Hash]common.Address - m sync.RWMutex -} - -func (sb *SwapBackend) add(tx common.Hash, ethAddr common.Address) { - sb.m.Lock() - defer sb.m.Unlock() - - sb.addrs[tx] = ethAddr -} - -func (sb *SwapBackend) remove(tx common.Hash) { - sb.m.Lock() - defer sb.m.Unlock() - - delete(sb.addrs, tx) -} - -func (sb *SwapBackend) TransactionReceipt(ctx context.Context, txHash common.Hash) (*types.Receipt, error) { - sb.m.RLock() - defer sb.m.RUnlock() - - return &types.Receipt{ - ContractAddress: sb.addrs[txHash], - }, nil -} diff --git a/pkg/settlement/swap/transaction/sender_validator.go b/pkg/settlement/swap/transaction/sender_validator.go new file mode 100644 index 00000000000..8998dba4b97 --- /dev/null +++ b/pkg/settlement/swap/transaction/sender_validator.go @@ -0,0 +1,46 @@ +package transaction + +import ( + "context" + "fmt" + "math/big" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethersphere/bee/pkg/crypto" + "github.com/ethersphere/bee/pkg/swarm" +) + +type validator struct { + backend Backend + signer types.Signer +} + +func NewValidator(backend Backend, chainID int64) validator { + return validator{ + backend: backend, + signer: types.NewEIP155Signer(big.NewInt(chainID)), + } +} + +func (s validator) MatchesSender(ctx context.Context, tx string, networkID uint64, senderOverlay swarm.Address) (bool, error) { + incomingTx := common.HexToHash(tx) + + nTx, isPending, err := s.backend.TransactionByHash(ctx, incomingTx) + if err != nil { + return false, err + } + + if isPending { + return false, fmt.Errorf("transaction still pending") + } + + sender, err := types.Sender(nil, nTx) + if err != nil { + return false, err + } + + expectedRemoteBzzAddress := crypto.NewOverlayFromEthereumAddress(sender.Bytes(), networkID) + + return expectedRemoteBzzAddress.Equal(senderOverlay), nil +} From 9855d615e9388e02307b88bad9f4c97fb5529065 Mon Sep 17 00:00:00 2001 From: Anatol Lupacescu Date: Fri, 7 May 2021 14:20:08 +0300 Subject: [PATCH 07/12] fix linter issues --- pkg/node/node.go | 4 +- .../libp2p/internal/handshake/handshake.go | 14 +++---- .../internal/handshake/handshake_test.go | 37 ++++++++++--------- pkg/p2p/libp2p/libp2p_test.go | 10 +++-- ...{sender_validator.go => sender_matcher.go} | 12 +++--- 5 files changed, 40 insertions(+), 37 deletions(-) rename pkg/settlement/swap/transaction/{sender_validator.go => sender_matcher.go} (72%) diff --git a/pkg/node/node.go b/pkg/node/node.go index 2af9d890702..d09ba954e2a 100644 --- a/pkg/node/node.go +++ b/pkg/node/node.go @@ -279,9 +279,9 @@ func NewBee(addr string, swarmAddress swarm.Address, publicKey ecdsa.PublicKey, return nil, err } - vd := transaction.NewValidator(swapBackend, chainID) + vd := transaction.NewMatcher(swapBackend, chainID) - p2ps, err := libp2p.New(p2pCtx, signer, networkID, swarmAddress, addr, addressbook, stateStore, lightNodes, vd.MatchesSender, logger, tracer, libp2p.Options{ + p2ps, err := libp2p.New(p2pCtx, signer, networkID, swarmAddress, addr, addressbook, stateStore, lightNodes, vd, logger, tracer, libp2p.Options{ PrivateKey: libp2pPrivateKey, NATAddr: o.NATAddr, EnableWS: o.EnableWS, diff --git a/pkg/p2p/libp2p/internal/handshake/handshake.go b/pkg/p2p/libp2p/internal/handshake/handshake.go index b1f8c494fc1..c8e939fed93 100644 --- a/pkg/p2p/libp2p/internal/handshake/handshake.go +++ b/pkg/p2p/libp2p/internal/handshake/handshake.go @@ -12,8 +12,6 @@ import ( "sync/atomic" "time" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/types" "github.com/ethersphere/bee/pkg/bzz" "github.com/ethersphere/bee/pkg/crypto" "github.com/ethersphere/bee/pkg/logging" @@ -64,15 +62,15 @@ type AdvertisableAddressResolver interface { Resolve(observedAdddress ma.Multiaddr) (ma.Multiaddr, error) } -type SwapBackend interface { - TransactionReceipt(ctx context.Context, txHash common.Hash) (*types.Receipt, error) +type SenderMatcher interface { + Matches(ctx context.Context, tx string, networkID uint64, senderOverlay swarm.Address) (bool, error) } // Service can perform initiate or handle a handshake between peers. type Service struct { signer crypto.Signer advertisableAddresser AdvertisableAddressResolver - isSender SenderMatcher + senderMatcher SenderMatcher overlay swarm.Address fullNode bool transaction string @@ -99,8 +97,6 @@ func (i *Info) LightString() string { return "" } -type SenderMatcher func(context.Context, string, uint64, swarm.Address) (bool, error) - // New creates a new handshake Service. func New(signer crypto.Signer, advertisableAddresser AdvertisableAddressResolver, isSender SenderMatcher, overlay swarm.Address, networkID uint64, fullNode bool, transaction string, welcomeMessage string, logger logging.Logger) (*Service, error) { if len(welcomeMessage) > MaxWelcomeMessageLength { @@ -114,7 +110,7 @@ func New(signer crypto.Signer, advertisableAddresser AdvertisableAddressResolver networkID: networkID, fullNode: fullNode, transaction: transaction, - isSender: isSender, + senderMatcher: isSender, receivedHandshakes: make(map[libp2ppeer.ID]struct{}), logger: logger, Notifiee: new(network.NoopNotifiee), @@ -288,7 +284,7 @@ func (s *Service) Handle(ctx context.Context, stream p2p.Stream, remoteMultiaddr s.logger.Infof("greeting \"%s\" from peer: %s", ack.WelcomeMessage, remoteBzzAddress.Overlay.String()) } - matchesSender, err := s.isSender(ctx, ack.Transaction, s.networkID, remoteBzzAddress.Overlay) + matchesSender, err := s.senderMatcher.Matches(ctx, ack.Transaction, s.networkID, remoteBzzAddress.Overlay) if err != nil { return nil, err } diff --git a/pkg/p2p/libp2p/internal/handshake/handshake_test.go b/pkg/p2p/libp2p/internal/handshake/handshake_test.go index 949c27bd3a4..79b4f2a1bc7 100644 --- a/pkg/p2p/libp2p/internal/handshake/handshake_test.go +++ b/pkg/p2p/libp2p/internal/handshake/handshake_test.go @@ -92,12 +92,9 @@ func TestHandshake(t *testing.T) { } aaddresser := &AdvertisableAddresserMock{} + senderMatcher := &MockSenderMatcher{v: true} - swapBackend := func(context.Context, string, uint64, swarm.Address) (bool, error) { - return true, nil - } - - handshakeService, err := handshake.New(signer1, aaddresser, swapBackend, node1Info.BzzAddress.Overlay, networkID, true, "", testWelcomeMessage, logger) + handshakeService, err := handshake.New(signer1, aaddresser, senderMatcher, node1Info.BzzAddress.Overlay, networkID, true, "", testWelcomeMessage, logger) if err != nil { t.Fatal(err) } @@ -165,7 +162,7 @@ func TestHandshake(t *testing.T) { const LongMessage = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi consectetur urna ut lorem sollicitudin posuere. Donec sagittis laoreet sapien." expectedErr := handshake.ErrWelcomeMessageLength - _, err := handshake.New(signer1, aaddresser, swapBackend, node1Info.BzzAddress.Overlay, networkID, true, "", LongMessage, logger) + _, err := handshake.New(signer1, aaddresser, senderMatcher, node1Info.BzzAddress.Overlay, networkID, true, "", LongMessage, logger) if err == nil || err.Error() != expectedErr.Error() { t.Fatal("expected:", expectedErr, "got:", err) } @@ -373,7 +370,7 @@ func TestHandshake(t *testing.T) { }) t.Run("Handle - OK", func(t *testing.T) { - handshakeService, err := handshake.New(signer1, aaddresser, swapBackend, node1Info.BzzAddress.Overlay, networkID, true, "", "", logger) + handshakeService, err := handshake.New(signer1, aaddresser, senderMatcher, node1Info.BzzAddress.Overlay, networkID, true, "", "", logger) if err != nil { t.Fatal(err) } @@ -430,7 +427,7 @@ func TestHandshake(t *testing.T) { }) t.Run("Handle - read error ", func(t *testing.T) { - handshakeService, err := handshake.New(signer1, aaddresser, swapBackend, node1Info.BzzAddress.Overlay, networkID, true, "", "", logger) + handshakeService, err := handshake.New(signer1, aaddresser, senderMatcher, node1Info.BzzAddress.Overlay, networkID, true, "", "", logger) if err != nil { t.Fatal(err) } @@ -449,7 +446,7 @@ func TestHandshake(t *testing.T) { }) t.Run("Handle - write error ", func(t *testing.T) { - handshakeService, err := handshake.New(signer1, aaddresser, swapBackend, node1Info.BzzAddress.Overlay, networkID, true, "", "", logger) + handshakeService, err := handshake.New(signer1, aaddresser, senderMatcher, node1Info.BzzAddress.Overlay, networkID, true, "", "", logger) if err != nil { t.Fatal(err) } @@ -476,7 +473,7 @@ func TestHandshake(t *testing.T) { }) t.Run("Handle - ack read error ", func(t *testing.T) { - handshakeService, err := handshake.New(signer1, aaddresser, swapBackend, node1Info.BzzAddress.Overlay, networkID, true, "", "", logger) + handshakeService, err := handshake.New(signer1, aaddresser, senderMatcher, node1Info.BzzAddress.Overlay, networkID, true, "", "", logger) if err != nil { t.Fatal(err) } @@ -505,7 +502,7 @@ func TestHandshake(t *testing.T) { }) t.Run("Handle - networkID mismatch ", func(t *testing.T) { - handshakeService, err := handshake.New(signer1, aaddresser, swapBackend, node1Info.BzzAddress.Overlay, networkID, true, "", "", logger) + handshakeService, err := handshake.New(signer1, aaddresser, senderMatcher, node1Info.BzzAddress.Overlay, networkID, true, "", "", logger) if err != nil { t.Fatal(err) } @@ -544,7 +541,7 @@ func TestHandshake(t *testing.T) { }) t.Run("Handle - duplicate handshake", func(t *testing.T) { - handshakeService, err := handshake.New(signer1, aaddresser, swapBackend, node1Info.BzzAddress.Overlay, networkID, true, "", "", logger) + handshakeService, err := handshake.New(signer1, aaddresser, senderMatcher, node1Info.BzzAddress.Overlay, networkID, true, "", "", logger) if err != nil { t.Fatal(err) } @@ -606,7 +603,7 @@ func TestHandshake(t *testing.T) { }) t.Run("Handle - invalid ack", func(t *testing.T) { - handshakeService, err := handshake.New(signer1, aaddresser, swapBackend, node1Info.BzzAddress.Overlay, networkID, true, "", "", logger) + handshakeService, err := handshake.New(signer1, aaddresser, senderMatcher, node1Info.BzzAddress.Overlay, networkID, true, "", "", logger) if err != nil { t.Fatal(err) } @@ -641,9 +638,7 @@ func TestHandshake(t *testing.T) { }) t.Run("Handle - transaction is not on the blockchain", func(t *testing.T) { - sbMock := func(context.Context, string, uint64, swarm.Address) (bool, error) { - return false, nil - } + sbMock := &MockSenderMatcher{v: false} handshakeService, err := handshake.New(signer1, aaddresser, sbMock, node1Info.BzzAddress.Overlay, networkID, true, "0xff", "", logger) if err != nil { @@ -680,7 +675,7 @@ func TestHandshake(t *testing.T) { }) t.Run("Handle - advertisable error", func(t *testing.T) { - handshakeService, err := handshake.New(signer1, aaddresser, swapBackend, node1Info.BzzAddress.Overlay, networkID, true, "", "", logger) + handshakeService, err := handshake.New(signer1, aaddresser, senderMatcher, node1Info.BzzAddress.Overlay, networkID, true, "", "", logger) if err != nil { t.Fatal(err) } @@ -737,3 +732,11 @@ func (a *AdvertisableAddresserMock) Resolve(observedAdddress ma.Multiaddr) (ma.M return observedAdddress, nil } + +type MockSenderMatcher struct { + v bool +} + +func (m MockSenderMatcher) Matches(context.Context, string, uint64, swarm.Address) (bool, error) { + return m.v, nil +} diff --git a/pkg/p2p/libp2p/libp2p_test.go b/pkg/p2p/libp2p/libp2p_test.go index 6c839a9fb44..c4c3bf20ebb 100644 --- a/pkg/p2p/libp2p/libp2p_test.go +++ b/pkg/p2p/libp2p/libp2p_test.go @@ -74,9 +74,7 @@ func newService(t *testing.T, networkID uint64, o libp2pServiceOpts) (s *libp2p. opts := o.libp2pOpts opts.Transaction = hexutil.EncodeUint64(o.PrivateKey.Y.Uint64()) - senderMatcher := func(context.Context, string, uint64, swarm.Address) (bool, error) { - return true, nil - } + senderMatcher := &MockSenderMatcher{} s, err = libp2p.New(ctx, crypto.NewDefaultSigner(swarmKey), networkID, overlay, addr, o.Addressbook, statestore, lightnodes, senderMatcher, o.Logger, nil, opts) if err != nil { @@ -159,3 +157,9 @@ func serviceUnderlayAddress(t *testing.T, s *libp2p.Service) multiaddr.Multiaddr } return addrs[0] } + +type MockSenderMatcher struct{} + +func (m MockSenderMatcher) Matches(context.Context, string, uint64, swarm.Address) (bool, error) { + return true, nil +} diff --git a/pkg/settlement/swap/transaction/sender_validator.go b/pkg/settlement/swap/transaction/sender_matcher.go similarity index 72% rename from pkg/settlement/swap/transaction/sender_validator.go rename to pkg/settlement/swap/transaction/sender_matcher.go index 8998dba4b97..31afe02042f 100644 --- a/pkg/settlement/swap/transaction/sender_validator.go +++ b/pkg/settlement/swap/transaction/sender_matcher.go @@ -11,24 +11,24 @@ import ( "github.com/ethersphere/bee/pkg/swarm" ) -type validator struct { +type Matcher struct { backend Backend signer types.Signer } -func NewValidator(backend Backend, chainID int64) validator { - return validator{ +func NewMatcher(backend Backend, chainID int64) *Matcher { + return &Matcher{ backend: backend, signer: types.NewEIP155Signer(big.NewInt(chainID)), } } -func (s validator) MatchesSender(ctx context.Context, tx string, networkID uint64, senderOverlay swarm.Address) (bool, error) { +func (s Matcher) Matches(ctx context.Context, tx string, networkID uint64, senderOverlay swarm.Address) (bool, error) { incomingTx := common.HexToHash(tx) nTx, isPending, err := s.backend.TransactionByHash(ctx, incomingTx) if err != nil { - return false, err + return false, err //TODO wrap error } if isPending { @@ -37,7 +37,7 @@ func (s validator) MatchesSender(ctx context.Context, tx string, networkID uint6 sender, err := types.Sender(nil, nTx) if err != nil { - return false, err + return false, err //TODO wrap error } expectedRemoteBzzAddress := crypto.NewOverlayFromEthereumAddress(sender.Bytes(), networkID) From 685abfe1a8a5a642404d62e941e0ea25c05746d6 Mon Sep 17 00:00:00 2001 From: Anatol Lupacescu Date: Fri, 7 May 2021 15:31:11 +0300 Subject: [PATCH 08/12] add descriptive error --- pkg/node/node.go | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/pkg/node/node.go b/pkg/node/node.go index d09ba954e2a..4943e417c01 100644 --- a/pkg/node/node.go +++ b/pkg/node/node.go @@ -276,7 +276,7 @@ func NewBee(addr string, swarmAddress swarm.Address, publicKey ecdsa.PublicKey, txHash, err := getTxHash(stateStore, logger, o.Transaction) if err != nil { - return nil, err + return nil, errors.New("no transaction hash provided or found") } vd := transaction.NewMatcher(swapBackend, chainID) @@ -797,8 +797,6 @@ func getTxHash(stateStore storage.StateStorer, logger logging.Logger, transactio return transaction, nil } - logger.Info("no transaction hash provided, trying to fetch it from the state") - var txHash common.Hash key := chequebook.ChequebookDeploymentKey if err := stateStore.Get(key, &txHash); err != nil { From 0e6ad0eaae1b227b5dec9dc4c648be860eba6a6c Mon Sep 17 00:00:00 2001 From: Anatol Lupacescu Date: Fri, 7 May 2021 16:16:42 +0300 Subject: [PATCH 09/12] change signer approach --- pkg/node/node.go | 5 +-- .../swap/transaction/sender_matcher.go | 11 +++---- .../swap/transaction/sender_matcher_test.go | 33 +++++++++++++++++++ 3 files changed, 41 insertions(+), 8 deletions(-) create mode 100644 pkg/settlement/swap/transaction/sender_matcher_test.go diff --git a/pkg/node/node.go b/pkg/node/node.go index 4943e417c01..3be343e6b17 100644 --- a/pkg/node/node.go +++ b/pkg/node/node.go @@ -21,6 +21,7 @@ import ( "time" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/ethclient" "github.com/ethersphere/bee/pkg/accounting" "github.com/ethersphere/bee/pkg/addressbook" @@ -279,9 +280,9 @@ func NewBee(addr string, swarmAddress swarm.Address, publicKey ecdsa.PublicKey, return nil, errors.New("no transaction hash provided or found") } - vd := transaction.NewMatcher(swapBackend, chainID) + senderMatcher := transaction.NewMatcher(swapBackend, types.NewEIP155Signer(big.NewInt(chainID))) - p2ps, err := libp2p.New(p2pCtx, signer, networkID, swarmAddress, addr, addressbook, stateStore, lightNodes, vd, logger, tracer, libp2p.Options{ + p2ps, err := libp2p.New(p2pCtx, signer, networkID, swarmAddress, addr, addressbook, stateStore, lightNodes, senderMatcher, logger, tracer, libp2p.Options{ PrivateKey: libp2pPrivateKey, NATAddr: o.NATAddr, EnableWS: o.EnableWS, diff --git a/pkg/settlement/swap/transaction/sender_matcher.go b/pkg/settlement/swap/transaction/sender_matcher.go index 31afe02042f..b27943c4df8 100644 --- a/pkg/settlement/swap/transaction/sender_matcher.go +++ b/pkg/settlement/swap/transaction/sender_matcher.go @@ -3,7 +3,6 @@ package transaction import ( "context" "fmt" - "math/big" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" @@ -16,17 +15,17 @@ type Matcher struct { signer types.Signer } -func NewMatcher(backend Backend, chainID int64) *Matcher { +func NewMatcher(backend Backend, signer types.Signer) *Matcher { return &Matcher{ backend: backend, - signer: types.NewEIP155Signer(big.NewInt(chainID)), + signer: signer, } } -func (s Matcher) Matches(ctx context.Context, tx string, networkID uint64, senderOverlay swarm.Address) (bool, error) { +func (m Matcher) Matches(ctx context.Context, tx string, networkID uint64, senderOverlay swarm.Address) (bool, error) { incomingTx := common.HexToHash(tx) - nTx, isPending, err := s.backend.TransactionByHash(ctx, incomingTx) + nTx, isPending, err := m.backend.TransactionByHash(ctx, incomingTx) if err != nil { return false, err //TODO wrap error } @@ -35,7 +34,7 @@ func (s Matcher) Matches(ctx context.Context, tx string, networkID uint64, sende return false, fmt.Errorf("transaction still pending") } - sender, err := types.Sender(nil, nTx) + sender, err := types.Sender(m.signer, nTx) if err != nil { return false, err //TODO wrap error } diff --git a/pkg/settlement/swap/transaction/sender_matcher_test.go b/pkg/settlement/swap/transaction/sender_matcher_test.go new file mode 100644 index 00000000000..7f30dd44cdc --- /dev/null +++ b/pkg/settlement/swap/transaction/sender_matcher_test.go @@ -0,0 +1,33 @@ +package transaction_test + +import ( + "context" + "testing" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethersphere/bee/pkg/settlement/swap/transaction" + "github.com/ethersphere/bee/pkg/settlement/swap/transaction/backendmock" + "github.com/ethersphere/bee/pkg/swarm" +) + +func TestMatchesSender(t *testing.T) { + t.Skip() + + txByHash := backendmock.WithTransactionByHashFunc(func(ctx context.Context, txHash common.Hash) (*types.Transaction, bool, error) { + return nil, false, nil + }) + matcher := transaction.NewMatcher(backendmock.New(txByHash), &types.HomesteadSigner{}) + _, err := matcher.Matches(context.Background(), "0x123", 0, swarm.NewAddress([]byte{})) + if err != nil { + t.Fatal(err) + } + // WIP +} + +// type mockSigner struct { +// } + +// func (*mockSigner) Sender(tx *types.Transaction) (common.Address, error) { +// return common.Address{}, nil +// } From 60567e8ed4543720c9c7d2c048f3bd84f903e3bd Mon Sep 17 00:00:00 2001 From: Anatol Lupacescu Date: Mon, 10 May 2021 17:21:15 +0300 Subject: [PATCH 10/12] add sender matcher test --- .../swap/transaction/sender_matcher.go | 13 +- .../swap/transaction/sender_matcher_test.go | 130 ++++++++++++++++-- 2 files changed, 126 insertions(+), 17 deletions(-) diff --git a/pkg/settlement/swap/transaction/sender_matcher.go b/pkg/settlement/swap/transaction/sender_matcher.go index b27943c4df8..0528e215c32 100644 --- a/pkg/settlement/swap/transaction/sender_matcher.go +++ b/pkg/settlement/swap/transaction/sender_matcher.go @@ -2,6 +2,7 @@ package transaction import ( "context" + "errors" "fmt" "github.com/ethereum/go-ethereum/common" @@ -15,6 +16,12 @@ type Matcher struct { signer types.Signer } +var ( + ErrTransactionNotFound = errors.New("transaction not found") + ErrTransactionPending = errors.New("transaction in pending status") + ErrTransactionSender = errors.New("transaction sender") +) + func NewMatcher(backend Backend, signer types.Signer) *Matcher { return &Matcher{ backend: backend, @@ -27,16 +34,16 @@ func (m Matcher) Matches(ctx context.Context, tx string, networkID uint64, sende nTx, isPending, err := m.backend.TransactionByHash(ctx, incomingTx) if err != nil { - return false, err //TODO wrap error + return false, fmt.Errorf("%v: %w", err, ErrTransactionNotFound) } if isPending { - return false, fmt.Errorf("transaction still pending") + return false, ErrTransactionPending } sender, err := types.Sender(m.signer, nTx) if err != nil { - return false, err //TODO wrap error + return false, fmt.Errorf("%v: %w", err, ErrTransactionSender) } expectedRemoteBzzAddress := crypto.NewOverlayFromEthereumAddress(sender.Bytes(), networkID) diff --git a/pkg/settlement/swap/transaction/sender_matcher_test.go b/pkg/settlement/swap/transaction/sender_matcher_test.go index 7f30dd44cdc..e2c1f5c43df 100644 --- a/pkg/settlement/swap/transaction/sender_matcher_test.go +++ b/pkg/settlement/swap/transaction/sender_matcher_test.go @@ -2,32 +2,134 @@ package transaction_test import ( "context" + "errors" + "math/big" "testing" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" + "github.com/ethersphere/bee/pkg/crypto" "github.com/ethersphere/bee/pkg/settlement/swap/transaction" "github.com/ethersphere/bee/pkg/settlement/swap/transaction/backendmock" "github.com/ethersphere/bee/pkg/swarm" ) func TestMatchesSender(t *testing.T) { - t.Skip() + recipient := common.HexToAddress("0xabcd") + txData := common.Hex2Bytes("0xabcdee") + value := big.NewInt(1) + suggestedGasPrice := big.NewInt(2) + estimatedGasLimit := uint64(3) + nonce := uint64(2) - txByHash := backendmock.WithTransactionByHashFunc(func(ctx context.Context, txHash common.Hash) (*types.Transaction, bool, error) { - return nil, false, nil + signedTx := types.NewTransaction(nonce, recipient, value, estimatedGasLimit, suggestedGasPrice, txData) + + t.Run("fail to retrieve tx from backend", func(t *testing.T) { + txByHash := backendmock.WithTransactionByHashFunc(func(ctx context.Context, txHash common.Hash) (*types.Transaction, bool, error) { + return nil, false, errors.New("transaction not found by hash") + }) + + matcher := transaction.NewMatcher(backendmock.New(txByHash), nil) + + _, err := matcher.Matches(context.Background(), "0x123", 0, swarm.NewAddress([]byte{})) + if !errors.Is(err, transaction.ErrTransactionNotFound) { + t.Fatalf("bad error type, want %v, got %v", transaction.ErrTransactionNotFound, err) + } + }) + + t.Run("transaction in 'pending' status", func(t *testing.T) { + txByHash := backendmock.WithTransactionByHashFunc(func(ctx context.Context, txHash common.Hash) (*types.Transaction, bool, error) { + return nil, true, nil + }) + + matcher := transaction.NewMatcher(backendmock.New(txByHash), nil) + + _, err := matcher.Matches(context.Background(), "0x123", 0, swarm.NewAddress([]byte{})) + if !errors.Is(err, transaction.ErrTransactionPending) { + t.Fatalf("bad error type, want %v, got %v", transaction.ErrTransactionPending, err) + } + }) + + t.Run("signer error", func(t *testing.T) { + txByHash := backendmock.WithTransactionByHashFunc(func(ctx context.Context, txHash common.Hash) (*types.Transaction, bool, error) { + return signedTx, false, nil + }) + + signer := &mockSigner{ + err: errors.New("can not sign"), + } + + matcher := transaction.NewMatcher(backendmock.New(txByHash), signer) + + _, err := matcher.Matches(context.Background(), "0x123", 0, swarm.NewAddress([]byte{})) + if !errors.Is(err, transaction.ErrTransactionSender) { + t.Fatalf("bad error type, want %v, got %v", transaction.ErrTransactionSender, err) + } + }) + + t.Run("sender does not match", func(t *testing.T) { + txByHash := backendmock.WithTransactionByHashFunc(func(ctx context.Context, txHash common.Hash) (*types.Transaction, bool, error) { + return signedTx, false, nil + }) + + signer := &mockSigner{ + addr: common.HexToAddress("0xabc"), + } + + matcher := transaction.NewMatcher(backendmock.New(txByHash), signer) + + matches, err := matcher.Matches(context.Background(), "0x123", 0, swarm.NewAddress([]byte{})) + if err != nil { + t.Fatalf("expected no err, got %v", err) + } + + if matches { + t.Fatalf("expected no match, got %v", matches) + } + }) + + t.Run("sender matches", func(t *testing.T) { + txByHash := backendmock.WithTransactionByHashFunc(func(ctx context.Context, txHash common.Hash) (*types.Transaction, bool, error) { + return signedTx, false, nil + }) + + signer := &mockSigner{ + addr: common.HexToAddress("0xff"), + } + + matcher := transaction.NewMatcher(backendmock.New(txByHash), signer) + + senderOverlay := crypto.NewOverlayFromEthereumAddress(signer.addr.Bytes(), 0) + + matches, err := matcher.Matches(context.Background(), "0x123", 0, senderOverlay) + if err != nil { + t.Fatalf("expected no err, got %v", err) + } + + if !matches { + t.Fatalf("expected match, got %v", matches) + } }) - matcher := transaction.NewMatcher(backendmock.New(txByHash), &types.HomesteadSigner{}) - _, err := matcher.Matches(context.Background(), "0x123", 0, swarm.NewAddress([]byte{})) - if err != nil { - t.Fatal(err) - } - // WIP } -// type mockSigner struct { -// } +type mockSigner struct { + addr common.Address + err error +} + +func (m *mockSigner) Sender(tx *types.Transaction) (common.Address, error) { + return m.addr, m.err +} + +func (*mockSigner) SignatureValues(tx *types.Transaction, sig []byte) (r, s, v *big.Int, err error) { + zero := big.NewInt(0) + return zero, zero, zero, nil +} + +func (*mockSigner) Hash(tx *types.Transaction) common.Hash { + return common.HexToHash("0xf") +} -// func (*mockSigner) Sender(tx *types.Transaction) (common.Address, error) { -// return common.Address{}, nil -// } +func (*mockSigner) Equal(types.Signer) bool { + return false +} From 01d530738c7445e16c9b34af6ebf3e3bc1954d7b Mon Sep 17 00:00:00 2001 From: Anatol Lupacescu Date: Tue, 11 May 2021 11:34:10 +0300 Subject: [PATCH 11/12] fixes in naming --- cmd/bee/cmd/cmd.go | 4 ++-- cmd/bee/cmd/start.go | 2 +- pkg/settlement/swap/transaction/sender_matcher.go | 8 ++++---- pkg/settlement/swap/transaction/sender_matcher_test.go | 4 ++-- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/cmd/bee/cmd/cmd.go b/cmd/bee/cmd/cmd.go index 0ad37dd1aef..6b24d4db54c 100644 --- a/cmd/bee/cmd/cmd.go +++ b/cmd/bee/cmd/cmd.go @@ -58,7 +58,7 @@ const ( optionNameSwapFactoryAddress = "swap-factory-address" optionNameSwapInitialDeposit = "swap-initial-deposit" optionNameSwapEnable = "swap-enable" - optionNameTransaction = "transaction" + optionNameTransactionHash = "transaction" optionNameFullNode = "full-node" optionNamePostageContractAddress = "postage-stamp-address" optionNamePriceOracleAddress = "price-oracle-address" @@ -231,7 +231,7 @@ func (c *command) setAllFlags(cmd *cobra.Command) { cmd.Flags().Bool(optionNameFullNode, false, "cause the node to start in full mode") cmd.Flags().String(optionNamePostageContractAddress, "", "postage stamp contract address") cmd.Flags().String(optionNamePriceOracleAddress, "", "price oracle address") - cmd.Flags().String(optionNameTransaction, "", "transaction hash") + cmd.Flags().String(optionNameTransactionHash, "", "proof-of-identity transaction hash") } func newLogger(cmd *cobra.Command, verbosity string) (logging.Logger, error) { diff --git a/cmd/bee/cmd/start.go b/cmd/bee/cmd/start.go index 18517a01cb0..b2f5433108d 100644 --- a/cmd/bee/cmd/start.go +++ b/cmd/bee/cmd/start.go @@ -148,7 +148,7 @@ Welcome to the Swarm.... Bzzz Bzzzz Bzzzz SwapInitialDeposit: c.config.GetString(optionNameSwapInitialDeposit), SwapEnable: c.config.GetBool(optionNameSwapEnable), FullNodeMode: fullNode, - Transaction: c.config.GetString(optionNameTransaction), + Transaction: c.config.GetString(optionNameTransactionHash), PostageContractAddress: c.config.GetString(optionNamePostageContractAddress), PriceOracleAddress: c.config.GetString(optionNamePriceOracleAddress), }) diff --git a/pkg/settlement/swap/transaction/sender_matcher.go b/pkg/settlement/swap/transaction/sender_matcher.go index 0528e215c32..476d656d4d3 100644 --- a/pkg/settlement/swap/transaction/sender_matcher.go +++ b/pkg/settlement/swap/transaction/sender_matcher.go @@ -17,9 +17,9 @@ type Matcher struct { } var ( - ErrTransactionNotFound = errors.New("transaction not found") - ErrTransactionPending = errors.New("transaction in pending status") - ErrTransactionSender = errors.New("transaction sender") + ErrTransactionNotFound = errors.New("transaction not found") + ErrTransactionPending = errors.New("transaction in pending status") + ErrTransactionSenderInvalid = errors.New("invalid transaction sender") ) func NewMatcher(backend Backend, signer types.Signer) *Matcher { @@ -43,7 +43,7 @@ func (m Matcher) Matches(ctx context.Context, tx string, networkID uint64, sende sender, err := types.Sender(m.signer, nTx) if err != nil { - return false, fmt.Errorf("%v: %w", err, ErrTransactionSender) + return false, fmt.Errorf("%v: %w", err, ErrTransactionSenderInvalid) } expectedRemoteBzzAddress := crypto.NewOverlayFromEthereumAddress(sender.Bytes(), networkID) diff --git a/pkg/settlement/swap/transaction/sender_matcher_test.go b/pkg/settlement/swap/transaction/sender_matcher_test.go index e2c1f5c43df..c146036670d 100644 --- a/pkg/settlement/swap/transaction/sender_matcher_test.go +++ b/pkg/settlement/swap/transaction/sender_matcher_test.go @@ -62,8 +62,8 @@ func TestMatchesSender(t *testing.T) { matcher := transaction.NewMatcher(backendmock.New(txByHash), signer) _, err := matcher.Matches(context.Background(), "0x123", 0, swarm.NewAddress([]byte{})) - if !errors.Is(err, transaction.ErrTransactionSender) { - t.Fatalf("bad error type, want %v, got %v", transaction.ErrTransactionSender, err) + if !errors.Is(err, transaction.ErrTransactionSenderInvalid) { + t.Fatalf("bad error type, want %v, got %v", transaction.ErrTransactionSenderInvalid, err) } }) From 6bd1e48f3d2251ca27173f6a04f01585af1a0d68 Mon Sep 17 00:00:00 2001 From: Anatol Lupacescu Date: Tue, 11 May 2021 11:53:25 +0300 Subject: [PATCH 12/12] bytes type for transaction field in handshake --- pkg/node/node.go | 8 ++-- .../libp2p/internal/handshake/handshake.go | 6 +-- .../internal/handshake/handshake_test.go | 24 +++++------ .../internal/handshake/pb/handshake.pb.go | 40 ++++++++++--------- .../internal/handshake/pb/handshake.proto | 2 +- pkg/p2p/libp2p/libp2p.go | 2 +- pkg/p2p/libp2p/libp2p_test.go | 4 +- .../swap/transaction/sender_matcher.go | 4 +- .../swap/transaction/sender_matcher_test.go | 10 ++--- 9 files changed, 51 insertions(+), 49 deletions(-) diff --git a/pkg/node/node.go b/pkg/node/node.go index 3be343e6b17..3f2d86dcceb 100644 --- a/pkg/node/node.go +++ b/pkg/node/node.go @@ -792,17 +792,17 @@ func (e *multiError) hasErrors() bool { return len(e.errors) > 0 } -func getTxHash(stateStore storage.StateStorer, logger logging.Logger, transaction string) (string, error) { +func getTxHash(stateStore storage.StateStorer, logger logging.Logger, transaction string) ([]byte, error) { if len(transaction) == 32 { logger.Info("using the provided transaction hash") - return transaction, nil + return []byte(transaction), nil } var txHash common.Hash key := chequebook.ChequebookDeploymentKey if err := stateStore.Get(key, &txHash); err != nil { - return "", err + return nil, err } - return txHash.String(), nil + return txHash.Bytes(), nil } diff --git a/pkg/p2p/libp2p/internal/handshake/handshake.go b/pkg/p2p/libp2p/internal/handshake/handshake.go index c8e939fed93..78735dcfa7c 100644 --- a/pkg/p2p/libp2p/internal/handshake/handshake.go +++ b/pkg/p2p/libp2p/internal/handshake/handshake.go @@ -63,7 +63,7 @@ type AdvertisableAddressResolver interface { } type SenderMatcher interface { - Matches(ctx context.Context, tx string, networkID uint64, senderOverlay swarm.Address) (bool, error) + Matches(ctx context.Context, tx []byte, networkID uint64, senderOverlay swarm.Address) (bool, error) } // Service can perform initiate or handle a handshake between peers. @@ -73,7 +73,7 @@ type Service struct { senderMatcher SenderMatcher overlay swarm.Address fullNode bool - transaction string + transaction []byte networkID uint64 welcomeMessage atomic.Value receivedHandshakes map[libp2ppeer.ID]struct{} @@ -98,7 +98,7 @@ func (i *Info) LightString() string { } // New creates a new handshake Service. -func New(signer crypto.Signer, advertisableAddresser AdvertisableAddressResolver, isSender SenderMatcher, overlay swarm.Address, networkID uint64, fullNode bool, transaction string, welcomeMessage string, logger logging.Logger) (*Service, error) { +func New(signer crypto.Signer, advertisableAddresser AdvertisableAddressResolver, isSender SenderMatcher, overlay swarm.Address, networkID uint64, fullNode bool, transaction []byte, welcomeMessage string, logger logging.Logger) (*Service, error) { if len(welcomeMessage) > MaxWelcomeMessageLength { return nil, ErrWelcomeMessageLength } diff --git a/pkg/p2p/libp2p/internal/handshake/handshake_test.go b/pkg/p2p/libp2p/internal/handshake/handshake_test.go index 79b4f2a1bc7..e2457c4173d 100644 --- a/pkg/p2p/libp2p/internal/handshake/handshake_test.go +++ b/pkg/p2p/libp2p/internal/handshake/handshake_test.go @@ -94,7 +94,7 @@ func TestHandshake(t *testing.T) { aaddresser := &AdvertisableAddresserMock{} senderMatcher := &MockSenderMatcher{v: true} - handshakeService, err := handshake.New(signer1, aaddresser, senderMatcher, node1Info.BzzAddress.Overlay, networkID, true, "", testWelcomeMessage, logger) + handshakeService, err := handshake.New(signer1, aaddresser, senderMatcher, node1Info.BzzAddress.Overlay, networkID, true, nil, testWelcomeMessage, logger) if err != nil { t.Fatal(err) } @@ -162,7 +162,7 @@ func TestHandshake(t *testing.T) { const LongMessage = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi consectetur urna ut lorem sollicitudin posuere. Donec sagittis laoreet sapien." expectedErr := handshake.ErrWelcomeMessageLength - _, err := handshake.New(signer1, aaddresser, senderMatcher, node1Info.BzzAddress.Overlay, networkID, true, "", LongMessage, logger) + _, err := handshake.New(signer1, aaddresser, senderMatcher, node1Info.BzzAddress.Overlay, networkID, true, nil, LongMessage, logger) if err == nil || err.Error() != expectedErr.Error() { t.Fatal("expected:", expectedErr, "got:", err) } @@ -370,7 +370,7 @@ func TestHandshake(t *testing.T) { }) t.Run("Handle - OK", func(t *testing.T) { - handshakeService, err := handshake.New(signer1, aaddresser, senderMatcher, node1Info.BzzAddress.Overlay, networkID, true, "", "", logger) + handshakeService, err := handshake.New(signer1, aaddresser, senderMatcher, node1Info.BzzAddress.Overlay, networkID, true, nil, "", logger) if err != nil { t.Fatal(err) } @@ -427,7 +427,7 @@ func TestHandshake(t *testing.T) { }) t.Run("Handle - read error ", func(t *testing.T) { - handshakeService, err := handshake.New(signer1, aaddresser, senderMatcher, node1Info.BzzAddress.Overlay, networkID, true, "", "", logger) + handshakeService, err := handshake.New(signer1, aaddresser, senderMatcher, node1Info.BzzAddress.Overlay, networkID, true, nil, "", logger) if err != nil { t.Fatal(err) } @@ -446,7 +446,7 @@ func TestHandshake(t *testing.T) { }) t.Run("Handle - write error ", func(t *testing.T) { - handshakeService, err := handshake.New(signer1, aaddresser, senderMatcher, node1Info.BzzAddress.Overlay, networkID, true, "", "", logger) + handshakeService, err := handshake.New(signer1, aaddresser, senderMatcher, node1Info.BzzAddress.Overlay, networkID, true, nil, "", logger) if err != nil { t.Fatal(err) } @@ -473,7 +473,7 @@ func TestHandshake(t *testing.T) { }) t.Run("Handle - ack read error ", func(t *testing.T) { - handshakeService, err := handshake.New(signer1, aaddresser, senderMatcher, node1Info.BzzAddress.Overlay, networkID, true, "", "", logger) + handshakeService, err := handshake.New(signer1, aaddresser, senderMatcher, node1Info.BzzAddress.Overlay, networkID, true, nil, "", logger) if err != nil { t.Fatal(err) } @@ -502,7 +502,7 @@ func TestHandshake(t *testing.T) { }) t.Run("Handle - networkID mismatch ", func(t *testing.T) { - handshakeService, err := handshake.New(signer1, aaddresser, senderMatcher, node1Info.BzzAddress.Overlay, networkID, true, "", "", logger) + handshakeService, err := handshake.New(signer1, aaddresser, senderMatcher, node1Info.BzzAddress.Overlay, networkID, true, nil, "", logger) if err != nil { t.Fatal(err) } @@ -541,7 +541,7 @@ func TestHandshake(t *testing.T) { }) t.Run("Handle - duplicate handshake", func(t *testing.T) { - handshakeService, err := handshake.New(signer1, aaddresser, senderMatcher, node1Info.BzzAddress.Overlay, networkID, true, "", "", logger) + handshakeService, err := handshake.New(signer1, aaddresser, senderMatcher, node1Info.BzzAddress.Overlay, networkID, true, nil, "", logger) if err != nil { t.Fatal(err) } @@ -603,7 +603,7 @@ func TestHandshake(t *testing.T) { }) t.Run("Handle - invalid ack", func(t *testing.T) { - handshakeService, err := handshake.New(signer1, aaddresser, senderMatcher, node1Info.BzzAddress.Overlay, networkID, true, "", "", logger) + handshakeService, err := handshake.New(signer1, aaddresser, senderMatcher, node1Info.BzzAddress.Overlay, networkID, true, nil, "", logger) if err != nil { t.Fatal(err) } @@ -640,7 +640,7 @@ func TestHandshake(t *testing.T) { t.Run("Handle - transaction is not on the blockchain", func(t *testing.T) { sbMock := &MockSenderMatcher{v: false} - handshakeService, err := handshake.New(signer1, aaddresser, sbMock, node1Info.BzzAddress.Overlay, networkID, true, "0xff", "", logger) + handshakeService, err := handshake.New(signer1, aaddresser, sbMock, node1Info.BzzAddress.Overlay, networkID, true, []byte("0xff"), "", logger) if err != nil { t.Fatal(err) } @@ -675,7 +675,7 @@ func TestHandshake(t *testing.T) { }) t.Run("Handle - advertisable error", func(t *testing.T) { - handshakeService, err := handshake.New(signer1, aaddresser, senderMatcher, node1Info.BzzAddress.Overlay, networkID, true, "", "", logger) + handshakeService, err := handshake.New(signer1, aaddresser, senderMatcher, node1Info.BzzAddress.Overlay, networkID, true, nil, "", logger) if err != nil { t.Fatal(err) } @@ -737,6 +737,6 @@ type MockSenderMatcher struct { v bool } -func (m MockSenderMatcher) Matches(context.Context, string, uint64, swarm.Address) (bool, error) { +func (m MockSenderMatcher) Matches(context.Context, []byte, uint64, swarm.Address) (bool, error) { return m.v, nil } diff --git a/pkg/p2p/libp2p/internal/handshake/pb/handshake.pb.go b/pkg/p2p/libp2p/internal/handshake/pb/handshake.pb.go index bfc434ab1e2..80c6c588dce 100644 --- a/pkg/p2p/libp2p/internal/handshake/pb/handshake.pb.go +++ b/pkg/p2p/libp2p/internal/handshake/pb/handshake.pb.go @@ -70,7 +70,7 @@ type Ack struct { Address *BzzAddress `protobuf:"bytes,1,opt,name=Address,proto3" json:"Address,omitempty"` NetworkID uint64 `protobuf:"varint,2,opt,name=NetworkID,proto3" json:"NetworkID,omitempty"` FullNode bool `protobuf:"varint,3,opt,name=FullNode,proto3" json:"FullNode,omitempty"` - Transaction string `protobuf:"bytes,4,opt,name=Transaction,proto3" json:"Transaction,omitempty"` + Transaction []byte `protobuf:"bytes,4,opt,name=Transaction,proto3" json:"Transaction,omitempty"` WelcomeMessage string `protobuf:"bytes,99,opt,name=WelcomeMessage,proto3" json:"WelcomeMessage,omitempty"` } @@ -128,11 +128,11 @@ func (m *Ack) GetFullNode() bool { return false } -func (m *Ack) GetTransaction() string { +func (m *Ack) GetTransaction() []byte { if m != nil { return m.Transaction } - return "" + return nil } func (m *Ack) GetWelcomeMessage() string { @@ -264,7 +264,7 @@ func init() { func init() { proto.RegisterFile("handshake.proto", fileDescriptor_a77305914d5d202f) } var fileDescriptor_a77305914d5d202f = []byte{ - // 323 bytes of a gzipped FileDescriptorProto + // 324 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x64, 0x91, 0xdf, 0x4a, 0xf3, 0x30, 0x18, 0xc6, 0x97, 0x75, 0xec, 0xcf, 0xbb, 0xb1, 0xef, 0x23, 0x20, 0x14, 0x19, 0x25, 0xf4, 0x40, 0x8a, 0x07, 0x13, 0xf5, 0x0a, 0x36, 0x44, 0x10, 0x74, 0x83, 0x54, 0x11, 0x3c, 0x32, 0x6b, 0xc3, @@ -277,15 +277,15 @@ var fileDescriptor_a77305914d5d202f = []byte{ 0x5b, 0x91, 0xee, 0x5c, 0xb8, 0x03, 0x8d, 0x01, 0x4f, 0x5e, 0xa5, 0x8a, 0x6e, 0xae, 0xec, 0x32, 0x41, 0x5e, 0x85, 0x16, 0x00, 0x1f, 0x43, 0xfd, 0x7a, 0x1e, 0xc7, 0x03, 0x19, 0x72, 0xdb, 0x22, 0xc8, 0xab, 0xd3, 0x7c, 0xc6, 0x04, 0x9a, 0xf7, 0x8a, 0x09, 0xcd, 0x82, 0x64, 0x2a, 0x85, 0x5d, - 0x21, 0xc8, 0x6b, 0xd0, 0x7d, 0x84, 0x4f, 0xa0, 0xfd, 0xc8, 0xe3, 0x40, 0xbe, 0xf0, 0x3b, 0xae, - 0x35, 0x1b, 0x73, 0x3b, 0x30, 0xa6, 0x03, 0xea, 0xde, 0x42, 0xd5, 0x4f, 0x45, 0x16, 0x9f, 0x98, - 0xe6, 0xdb, 0xe8, 0xed, 0xbd, 0xe8, 0x7e, 0x2a, 0xa8, 0x59, 0x0a, 0x31, 0x3d, 0x4d, 0xd2, 0xdf, - 0x8e, 0x5e, 0x10, 0xd1, 0x4c, 0x72, 0x9f, 0x01, 0x8a, 0xa2, 0x59, 0x83, 0x83, 0xe5, 0xe5, 0x73, - 0xd6, 0xdd, 0x9f, 0x8e, 0x05, 0x4b, 0xe6, 0x8a, 0x9b, 0x1b, 0x5b, 0xb4, 0x00, 0xd8, 0x86, 0xda, - 0x70, 0xf1, 0x73, 0xd0, 0x32, 0xda, 0x6e, 0xec, 0x77, 0x3e, 0xd6, 0x0e, 0x5a, 0xad, 0x1d, 0xf4, - 0xb5, 0x76, 0xd0, 0xdb, 0xc6, 0x29, 0xad, 0x36, 0x4e, 0xe9, 0x73, 0xe3, 0x94, 0x9e, 0xca, 0xb3, - 0xd1, 0xa8, 0x6a, 0xfe, 0xf3, 0xf2, 0x3b, 0x00, 0x00, 0xff, 0xff, 0xaf, 0x17, 0xf9, 0xa4, 0xe2, - 0x01, 0x00, 0x00, + 0x31, 0xc9, 0xf6, 0x11, 0x3e, 0x81, 0xf6, 0x23, 0x8f, 0x03, 0xf9, 0xc2, 0xef, 0xb8, 0xd6, 0x6c, + 0xcc, 0xed, 0x80, 0x20, 0xaf, 0x41, 0x0f, 0xa8, 0x7b, 0x0b, 0x55, 0x3f, 0x15, 0x59, 0x7c, 0x62, + 0x9a, 0x6f, 0xa3, 0xb7, 0xf7, 0xa2, 0xfb, 0xa9, 0xa0, 0x66, 0x29, 0xc4, 0xf4, 0x34, 0x49, 0x7f, + 0x3b, 0x7a, 0x41, 0x44, 0x33, 0xc9, 0x7d, 0x06, 0x28, 0x8a, 0x66, 0x0d, 0x0e, 0x96, 0x97, 0xcf, + 0x59, 0x77, 0x7f, 0x3a, 0x16, 0x2c, 0x99, 0x2b, 0x6e, 0x6e, 0x6c, 0xd1, 0x02, 0x60, 0x1b, 0x6a, + 0xc3, 0xc5, 0xcf, 0x41, 0xcb, 0x68, 0xbb, 0xb1, 0xdf, 0xf9, 0x58, 0x3b, 0x68, 0xb5, 0x76, 0xd0, + 0xd7, 0xda, 0x41, 0x6f, 0x1b, 0xa7, 0xb4, 0xda, 0x38, 0xa5, 0xcf, 0x8d, 0x53, 0x7a, 0x2a, 0xcf, + 0x46, 0xa3, 0xaa, 0xf9, 0xcf, 0xcb, 0xef, 0x00, 0x00, 0x00, 0xff, 0xff, 0xd1, 0x48, 0x2c, 0x4a, + 0xe2, 0x01, 0x00, 0x00, } func (m *Syn) Marshal() (dAtA []byte, err error) { @@ -765,7 +765,7 @@ func (m *Ack) Unmarshal(dAtA []byte) error { if wireType != 2 { return fmt.Errorf("proto: wrong wireType = %d for field Transaction", wireType) } - var stringLen uint64 + var byteLen int for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowHandshake @@ -775,23 +775,25 @@ func (m *Ack) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - stringLen |= uint64(b&0x7F) << shift + byteLen |= int(b&0x7F) << shift if b < 0x80 { break } } - intStringLen := int(stringLen) - if intStringLen < 0 { + if byteLen < 0 { return ErrInvalidLengthHandshake } - postIndex := iNdEx + intStringLen + postIndex := iNdEx + byteLen if postIndex < 0 { return ErrInvalidLengthHandshake } if postIndex > l { return io.ErrUnexpectedEOF } - m.Transaction = string(dAtA[iNdEx:postIndex]) + m.Transaction = append(m.Transaction[:0], dAtA[iNdEx:postIndex]...) + if m.Transaction == nil { + m.Transaction = []byte{} + } iNdEx = postIndex case 99: if wireType != 2 { diff --git a/pkg/p2p/libp2p/internal/handshake/pb/handshake.proto b/pkg/p2p/libp2p/internal/handshake/pb/handshake.proto index 4a5c6a9c365..f0c6597af3a 100644 --- a/pkg/p2p/libp2p/internal/handshake/pb/handshake.proto +++ b/pkg/p2p/libp2p/internal/handshake/pb/handshake.proto @@ -16,7 +16,7 @@ message Ack { BzzAddress Address = 1; uint64 NetworkID = 2; bool FullNode = 3; - string Transaction = 4; + bytes Transaction = 4; string WelcomeMessage = 99; } diff --git a/pkg/p2p/libp2p/libp2p.go b/pkg/p2p/libp2p/libp2p.go index 541d69daf77..1fda2266378 100644 --- a/pkg/p2p/libp2p/libp2p.go +++ b/pkg/p2p/libp2p/libp2p.go @@ -84,7 +84,7 @@ type Options struct { Standalone bool FullNode bool WelcomeMessage string - Transaction string + Transaction []byte } func New(ctx context.Context, signer beecrypto.Signer, networkID uint64, overlay swarm.Address, addr string, ab addressbook.Putter, storer storage.StateStorer, lightNodes *lightnode.Container, swapBackend handshake.SenderMatcher, logger logging.Logger, tracer *tracing.Tracer, o Options) (*Service, error) { diff --git a/pkg/p2p/libp2p/libp2p_test.go b/pkg/p2p/libp2p/libp2p_test.go index c4c3bf20ebb..507b62cb169 100644 --- a/pkg/p2p/libp2p/libp2p_test.go +++ b/pkg/p2p/libp2p/libp2p_test.go @@ -72,7 +72,7 @@ func newService(t *testing.T, networkID uint64, o libp2pServiceOpts) (s *libp2p. lightnodes := lightnode.NewContainer() opts := o.libp2pOpts - opts.Transaction = hexutil.EncodeUint64(o.PrivateKey.Y.Uint64()) + opts.Transaction = []byte(hexutil.EncodeUint64(o.PrivateKey.Y.Uint64())) senderMatcher := &MockSenderMatcher{} @@ -160,6 +160,6 @@ func serviceUnderlayAddress(t *testing.T, s *libp2p.Service) multiaddr.Multiaddr type MockSenderMatcher struct{} -func (m MockSenderMatcher) Matches(context.Context, string, uint64, swarm.Address) (bool, error) { +func (m MockSenderMatcher) Matches(context.Context, []byte, uint64, swarm.Address) (bool, error) { return true, nil } diff --git a/pkg/settlement/swap/transaction/sender_matcher.go b/pkg/settlement/swap/transaction/sender_matcher.go index 476d656d4d3..a3308bd331a 100644 --- a/pkg/settlement/swap/transaction/sender_matcher.go +++ b/pkg/settlement/swap/transaction/sender_matcher.go @@ -29,8 +29,8 @@ func NewMatcher(backend Backend, signer types.Signer) *Matcher { } } -func (m Matcher) Matches(ctx context.Context, tx string, networkID uint64, senderOverlay swarm.Address) (bool, error) { - incomingTx := common.HexToHash(tx) +func (m Matcher) Matches(ctx context.Context, tx []byte, networkID uint64, senderOverlay swarm.Address) (bool, error) { + incomingTx := common.BytesToHash(tx) nTx, isPending, err := m.backend.TransactionByHash(ctx, incomingTx) if err != nil { diff --git a/pkg/settlement/swap/transaction/sender_matcher_test.go b/pkg/settlement/swap/transaction/sender_matcher_test.go index c146036670d..6e0d75cfac9 100644 --- a/pkg/settlement/swap/transaction/sender_matcher_test.go +++ b/pkg/settlement/swap/transaction/sender_matcher_test.go @@ -31,7 +31,7 @@ func TestMatchesSender(t *testing.T) { matcher := transaction.NewMatcher(backendmock.New(txByHash), nil) - _, err := matcher.Matches(context.Background(), "0x123", 0, swarm.NewAddress([]byte{})) + _, err := matcher.Matches(context.Background(), []byte("0x123"), 0, swarm.NewAddress([]byte{})) if !errors.Is(err, transaction.ErrTransactionNotFound) { t.Fatalf("bad error type, want %v, got %v", transaction.ErrTransactionNotFound, err) } @@ -44,7 +44,7 @@ func TestMatchesSender(t *testing.T) { matcher := transaction.NewMatcher(backendmock.New(txByHash), nil) - _, err := matcher.Matches(context.Background(), "0x123", 0, swarm.NewAddress([]byte{})) + _, err := matcher.Matches(context.Background(), []byte("0x123"), 0, swarm.NewAddress([]byte{})) if !errors.Is(err, transaction.ErrTransactionPending) { t.Fatalf("bad error type, want %v, got %v", transaction.ErrTransactionPending, err) } @@ -61,7 +61,7 @@ func TestMatchesSender(t *testing.T) { matcher := transaction.NewMatcher(backendmock.New(txByHash), signer) - _, err := matcher.Matches(context.Background(), "0x123", 0, swarm.NewAddress([]byte{})) + _, err := matcher.Matches(context.Background(), []byte("0x123"), 0, swarm.NewAddress([]byte{})) if !errors.Is(err, transaction.ErrTransactionSenderInvalid) { t.Fatalf("bad error type, want %v, got %v", transaction.ErrTransactionSenderInvalid, err) } @@ -78,7 +78,7 @@ func TestMatchesSender(t *testing.T) { matcher := transaction.NewMatcher(backendmock.New(txByHash), signer) - matches, err := matcher.Matches(context.Background(), "0x123", 0, swarm.NewAddress([]byte{})) + matches, err := matcher.Matches(context.Background(), []byte("0x123"), 0, swarm.NewAddress([]byte{})) if err != nil { t.Fatalf("expected no err, got %v", err) } @@ -101,7 +101,7 @@ func TestMatchesSender(t *testing.T) { senderOverlay := crypto.NewOverlayFromEthereumAddress(signer.addr.Bytes(), 0) - matches, err := matcher.Matches(context.Background(), "0x123", 0, senderOverlay) + matches, err := matcher.Matches(context.Background(), []byte("0x123"), 0, senderOverlay) if err != nil { t.Fatalf("expected no err, got %v", err) }