From b81ec95c46eed31fdee12b6b4ee8c645dfc554e6 Mon Sep 17 00:00:00 2001 From: Vitaly Bogdanov Date: Mon, 3 Dec 2018 20:18:57 +0300 Subject: [PATCH 1/3] Add signer field and read it from blockchain. --- blockchain/escrow.go | 2 ++ escrow/escrow.go | 1 + escrow/escrow_test.go | 6 ++++++ escrow/payment_channel_api.go | 7 +++++-- escrow/payment_channel_storage.go | 1 + escrow/payment_channel_storage_test.go | 7 +++++++ escrow/state_service_test.go | 7 +++++++ escrow/validation_test.go | 5 +++++ 8 files changed, 34 insertions(+), 2 deletions(-) diff --git a/blockchain/escrow.go b/blockchain/escrow.go index 69de3a04..03870084 100644 --- a/blockchain/escrow.go +++ b/blockchain/escrow.go @@ -78,6 +78,7 @@ type MultiPartyEscrowChannel struct { Value *big.Int Nonce *big.Int Expiration *big.Int + Signer common.Address } var zeroAddress = common.Address{} @@ -102,6 +103,7 @@ func (processor *Processor) MultiPartyEscrowChannel(channelID *big.Int) (channel Value: ch.Value, Nonce: ch.Nonce, Expiration: ch.Expiration, + Signer: ch.Signer, } log = log.WithField("channel", channel) diff --git a/escrow/escrow.go b/escrow/escrow.go index 858ffff5..ec1116fb 100644 --- a/escrow/escrow.go +++ b/escrow/escrow.go @@ -216,6 +216,7 @@ func (payment *paymentTransaction) Commit() error { Recipient: payment.channel.Recipient, FullAmount: payment.channel.FullAmount, Expiration: payment.channel.Expiration, + Signer: payment.channel.Signer, AuthorizedAmount: payment.payment.Amount, Signature: payment.payment.Signature, GroupID: payment.channel.GroupID, diff --git a/escrow/escrow_test.go b/escrow/escrow_test.go index fc42d28b..b3049ed4 100644 --- a/escrow/escrow_test.go +++ b/escrow/escrow_test.go @@ -80,6 +80,8 @@ type PaymentChannelServiceSuite struct { senderPrivateKey *ecdsa.PrivateKey senderAddress common.Address + signerPrivateKey *ecdsa.PrivateKey + signerAddress common.Address recipientAddress common.Address mpeContractAddress common.Address memoryStorage *memoryStorage @@ -92,6 +94,8 @@ type PaymentChannelServiceSuite struct { func (suite *PaymentChannelServiceSuite) SetupSuite() { suite.senderPrivateKey = GenerateTestPrivateKey() suite.senderAddress = crypto.PubkeyToAddress(suite.senderPrivateKey.PublicKey) + suite.signerPrivateKey = GenerateTestPrivateKey() + suite.signerAddress = crypto.PubkeyToAddress(suite.signerPrivateKey.PublicKey) suite.recipientAddress = crypto.PubkeyToAddress(GenerateTestPrivateKey().PublicKey) suite.mpeContractAddress = blockchain.HexToAddress("0xf25186b5081ff5ce73482ad761db0eb0d25abfbf") suite.memoryStorage = NewMemStorage() @@ -141,6 +145,7 @@ func (suite *PaymentChannelServiceSuite) mpeChannel() *blockchain.MultiPartyEscr Value: big.NewInt(12345), Nonce: big.NewInt(3), Expiration: big.NewInt(100), + Signer: suite.signerAddress, } } @@ -170,6 +175,7 @@ func (suite *PaymentChannelServiceSuite) channel() *PaymentChannelData { GroupID: [32]byte{123}, FullAmount: big.NewInt(12345), Expiration: big.NewInt(100), + Signer: suite.signerAddress, AuthorizedAmount: big.NewInt(0), Signature: nil, } diff --git a/escrow/payment_channel_api.go b/escrow/payment_channel_api.go index c9a6b77a..f25c7b37 100644 --- a/escrow/payment_channel_api.go +++ b/escrow/payment_channel_api.go @@ -86,6 +86,9 @@ type PaymentChannelData struct { // expressed in Ethereum block number. Since this block is added to // blockchain Sender can withdraw tokens from channel. Expiration *big.Int + // Signer is and address to be used to sign the payments. Usually it is + // equal to channel sender. + Signer common.Address // service provider. This amount increments on price after each successful // RPC call. @@ -96,8 +99,8 @@ type PaymentChannelData struct { } func (data *PaymentChannelData) String() string { - return fmt.Sprintf("{ChannelID: %v, Nonce: %v, State: %v, Sender: %v, Recipient: %v, GroupId: %v, FullAmount: %v, Expiration: %v, AuthorizedAmount: %v, Signature: %v", - data.ChannelID, data.Nonce, data.State, blockchain.AddressToHex(&data.Sender), blockchain.AddressToHex(&data.Recipient), data.GroupID, data.FullAmount, data.Expiration, data.AuthorizedAmount, blockchain.BytesToBase64(data.Signature)) + return fmt.Sprintf("{ChannelID: %v, Nonce: %v, State: %v, Sender: %v, Recipient: %v, GroupId: %v, FullAmount: %v, Expiration: %v, Signer: %v, AuthorizedAmount: %v, Signature: %v", + data.ChannelID, data.Nonce, data.State, blockchain.AddressToHex(&data.Sender), blockchain.AddressToHex(&data.Recipient), data.GroupID, data.FullAmount, data.Expiration, data.Signer, data.AuthorizedAmount, blockchain.BytesToBase64(data.Signature)) } // PaymentChannelService interface is API for payment channel functionality. diff --git a/escrow/payment_channel_storage.go b/escrow/payment_channel_storage.go index 36ccacd8..3bc27492 100644 --- a/escrow/payment_channel_storage.go +++ b/escrow/payment_channel_storage.go @@ -147,6 +147,7 @@ func (reader *BlockchainChannelReader) GetChannelStateFromBlockchain(key *Paymen GroupID: ch.GroupId, FullAmount: ch.Value, Expiration: ch.Expiration, + Signer: ch.Signer, AuthorizedAmount: big.NewInt(0), Signature: nil, }, true, nil diff --git a/escrow/payment_channel_storage_test.go b/escrow/payment_channel_storage_test.go index ad7e8e70..39272379 100644 --- a/escrow/payment_channel_storage_test.go +++ b/escrow/payment_channel_storage_test.go @@ -26,6 +26,7 @@ type PaymentChannelStorageSuite struct { suite.Suite senderAddress common.Address + signerAddress common.Address recipientAddress common.Address memoryStorage *memoryStorage @@ -34,6 +35,7 @@ type PaymentChannelStorageSuite struct { func (suite *PaymentChannelStorageSuite) SetupSuite() { suite.senderAddress = crypto.PubkeyToAddress(GenerateTestPrivateKey().PublicKey) + suite.signerAddress = crypto.PubkeyToAddress(GenerateTestPrivateKey().PublicKey) suite.recipientAddress = crypto.PubkeyToAddress(GenerateTestPrivateKey().PublicKey) suite.memoryStorage = NewMemStorage() @@ -61,6 +63,7 @@ func (suite *PaymentChannelStorageSuite) channel() *PaymentChannelData { GroupID: [32]byte{123}, FullAmount: big.NewInt(12345), Expiration: big.NewInt(100), + Signer: suite.signerAddress, AuthorizedAmount: big.NewInt(0), Signature: nil, } @@ -83,12 +86,14 @@ type BlockchainChannelReaderSuite struct { senderAddress common.Address recipientAddress common.Address + signerAddress common.Address reader BlockchainChannelReader } func (suite *BlockchainChannelReaderSuite) SetupSuite() { suite.senderAddress = crypto.PubkeyToAddress(GenerateTestPrivateKey().PublicKey) + suite.signerAddress = crypto.PubkeyToAddress(GenerateTestPrivateKey().PublicKey) suite.recipientAddress = crypto.PubkeyToAddress(GenerateTestPrivateKey().PublicKey) suite.reader = BlockchainChannelReader{ @@ -115,6 +120,7 @@ func (suite *BlockchainChannelReaderSuite) mpeChannel() *blockchain.MultiPartyEs Value: big.NewInt(12345), Nonce: big.NewInt(3), Expiration: big.NewInt(100), + Signer: suite.signerAddress, } } @@ -127,6 +133,7 @@ func (suite *BlockchainChannelReaderSuite) channel() *PaymentChannelData { GroupID: [32]byte{123}, FullAmount: big.NewInt(12345), Expiration: big.NewInt(100), + Signer: suite.signerAddress, AuthorizedAmount: big.NewInt(0), Signature: nil, } diff --git a/escrow/state_service_test.go b/escrow/state_service_test.go index 29c79f21..7f31d16e 100644 --- a/escrow/state_service_test.go +++ b/escrow/state_service_test.go @@ -15,6 +15,8 @@ type stateServiceTestType struct { service PaymentChannelStateService senderPrivateKey *ecdsa.PrivateKey senderAddress common.Address + signerPrivateKey *ecdsa.PrivateKey + signerAddress common.Address channelServiceMock *paymentChannelServiceMock defaultChannelId *big.Int @@ -28,6 +30,8 @@ var stateServiceTest = func() stateServiceTestType { channelServiceMock := &paymentChannelServiceMock{} senderPrivateKey := GenerateTestPrivateKey() senderAddress := crypto.PubkeyToAddress(senderPrivateKey.PublicKey) + signerPrivateKey := GenerateTestPrivateKey() + signerAddress := crypto.PubkeyToAddress(signerPrivateKey.PublicKey) defaultChannelId := big.NewInt(42) defaultSignature, err := hex.DecodeString("0504030201") @@ -41,6 +45,8 @@ var stateServiceTest = func() stateServiceTestType { }, senderPrivateKey: senderPrivateKey, senderAddress: senderAddress, + signerPrivateKey: signerPrivateKey, + signerAddress: signerAddress, channelServiceMock: channelServiceMock, defaultChannelId: defaultChannelId, @@ -48,6 +54,7 @@ var stateServiceTest = func() stateServiceTestType { defaultChannelData: &PaymentChannelData{ ChannelID: defaultChannelId, Sender: senderAddress, + Signer: signerAddress, Signature: defaultSignature, Nonce: big.NewInt(3), AuthorizedAmount: big.NewInt(12345), diff --git a/escrow/validation_test.go b/escrow/validation_test.go index e940a60e..00053cf1 100644 --- a/escrow/validation_test.go +++ b/escrow/validation_test.go @@ -61,6 +61,8 @@ type ValidationTestSuite struct { senderPrivateKey *ecdsa.PrivateKey senderAddress common.Address + signerPrivateKey *ecdsa.PrivateKey + signerAddress common.Address recipientAddress common.Address mpeContractAddress common.Address @@ -74,6 +76,8 @@ func TestValidationTestSuite(t *testing.T) { func (suite *ValidationTestSuite) SetupSuite() { suite.senderPrivateKey = GenerateTestPrivateKey() suite.senderAddress = crypto.PubkeyToAddress(suite.senderPrivateKey.PublicKey) + suite.signerPrivateKey = GenerateTestPrivateKey() + suite.signerAddress = crypto.PubkeyToAddress(suite.signerPrivateKey.PublicKey) suite.recipientAddress = crypto.PubkeyToAddress(GenerateTestPrivateKey().PublicKey) suite.mpeContractAddress = blockchain.HexToAddress("0xf25186b5081ff5ce73482ad761db0eb0d25abfbf") @@ -103,6 +107,7 @@ func (suite *ValidationTestSuite) channel() *PaymentChannelData { GroupID: [32]byte{123}, FullAmount: big.NewInt(12345), Expiration: big.NewInt(100), + Signer: suite.signerAddress, AuthorizedAmount: big.NewInt(12300), Signature: nil, } From 45a7231a483a8ab7d4b76fdd64a3b3da29057d27 Mon Sep 17 00:00:00 2001 From: Vitaly Bogdanov Date: Mon, 3 Dec 2018 20:24:45 +0300 Subject: [PATCH 2/3] Replace channel sender sign validation by channel signer sign --- escrow/escrow_test.go | 18 ++++++++---------- escrow/validation.go | 6 +++--- escrow/validation_test.go | 12 +++++------- 3 files changed, 16 insertions(+), 20 deletions(-) diff --git a/escrow/escrow_test.go b/escrow/escrow_test.go index b3049ed4..143e0aa2 100644 --- a/escrow/escrow_test.go +++ b/escrow/escrow_test.go @@ -78,7 +78,6 @@ func (transaction *paymentTransactionMock) Rollback() error { type PaymentChannelServiceSuite struct { suite.Suite - senderPrivateKey *ecdsa.PrivateKey senderAddress common.Address signerPrivateKey *ecdsa.PrivateKey signerAddress common.Address @@ -92,8 +91,7 @@ type PaymentChannelServiceSuite struct { } func (suite *PaymentChannelServiceSuite) SetupSuite() { - suite.senderPrivateKey = GenerateTestPrivateKey() - suite.senderAddress = crypto.PubkeyToAddress(suite.senderPrivateKey.PublicKey) + suite.senderAddress = crypto.PubkeyToAddress(GenerateTestPrivateKey().PublicKey) suite.signerPrivateKey = GenerateTestPrivateKey() suite.signerAddress = crypto.PubkeyToAddress(suite.signerPrivateKey.PublicKey) suite.recipientAddress = crypto.PubkeyToAddress(GenerateTestPrivateKey().PublicKey) @@ -156,7 +154,7 @@ func (suite *PaymentChannelServiceSuite) payment() *Payment { ChannelNonce: big.NewInt(3), //MpeContractAddress: suite.mpeContractAddress, } - SignTestPayment(payment, suite.senderPrivateKey) + SignTestPayment(payment, suite.signerPrivateKey) return payment } @@ -205,10 +203,10 @@ func (suite *PaymentChannelServiceSuite) TestPaymentTransaction() { func (suite *PaymentChannelServiceSuite) TestPaymentParallelTransaction() { paymentA := suite.payment() paymentA.Amount = big.NewInt(13) - SignTestPayment(paymentA, suite.senderPrivateKey) + SignTestPayment(paymentA, suite.signerPrivateKey) paymentB := suite.payment() paymentB.Amount = big.NewInt(17) - SignTestPayment(paymentB, suite.senderPrivateKey) + SignTestPayment(paymentB, suite.signerPrivateKey) transactionA, errA := suite.service.StartPaymentTransaction(paymentA) transactionB, errB := suite.service.StartPaymentTransaction(paymentB) @@ -227,10 +225,10 @@ func (suite *PaymentChannelServiceSuite) TestPaymentParallelTransaction() { func (suite *PaymentChannelServiceSuite) TestPaymentSequentialTransaction() { paymentA := suite.payment() paymentA.Amount = big.NewInt(13) - SignTestPayment(paymentA, suite.senderPrivateKey) + SignTestPayment(paymentA, suite.signerPrivateKey) paymentB := suite.payment() paymentB.Amount = big.NewInt(17) - SignTestPayment(paymentB, suite.senderPrivateKey) + SignTestPayment(paymentB, suite.signerPrivateKey) transactionA, errA := suite.service.StartPaymentTransaction(paymentA) errAC := transactionA.Commit() @@ -250,10 +248,10 @@ func (suite *PaymentChannelServiceSuite) TestPaymentSequentialTransaction() { func (suite *PaymentChannelServiceSuite) TestPaymentSequentialTransactionAfterRollback() { paymentA := suite.payment() paymentA.Amount = big.NewInt(13) - SignTestPayment(paymentA, suite.senderPrivateKey) + SignTestPayment(paymentA, suite.signerPrivateKey) paymentB := suite.payment() paymentB.Amount = big.NewInt(13) - SignTestPayment(paymentB, suite.senderPrivateKey) + SignTestPayment(paymentB, suite.signerPrivateKey) transactionA, errA := suite.service.StartPaymentTransaction(paymentA) errAC := transactionA.Rollback() diff --git a/escrow/validation.go b/escrow/validation.go index d381a05c..54bdf3a4 100644 --- a/escrow/validation.go +++ b/escrow/validation.go @@ -45,9 +45,9 @@ func (validator *ChannelPaymentValidator) Validate(payment *Payment, channel *Pa } log = log.WithField("signerAddress", blockchain.AddressToHex(signerAddress)) - if *signerAddress != channel.Sender { - log.WithField("signerAddress", blockchain.AddressToHex(signerAddress)).Warn("Channel sender is not equal to payment signer") - return NewPaymentError(Unauthenticated, "payment is not signed by channel sender") + if *signerAddress != channel.Signer { + log.WithField("signerAddress", blockchain.AddressToHex(signerAddress)).Warn("Channel signer is not equal to payment signer") + return NewPaymentError(Unauthenticated, "payment is not signed by channel signer") } currentBlock, e := validator.currentBlock() if e != nil { diff --git a/escrow/validation_test.go b/escrow/validation_test.go index 00053cf1..e974d6c7 100644 --- a/escrow/validation_test.go +++ b/escrow/validation_test.go @@ -59,7 +59,6 @@ func GenerateTestPrivateKey() (privateKey *ecdsa.PrivateKey) { type ValidationTestSuite struct { suite.Suite - senderPrivateKey *ecdsa.PrivateKey senderAddress common.Address signerPrivateKey *ecdsa.PrivateKey signerAddress common.Address @@ -74,8 +73,7 @@ func TestValidationTestSuite(t *testing.T) { } func (suite *ValidationTestSuite) SetupSuite() { - suite.senderPrivateKey = GenerateTestPrivateKey() - suite.senderAddress = crypto.PubkeyToAddress(suite.senderPrivateKey.PublicKey) + suite.senderAddress = crypto.PubkeyToAddress(GenerateTestPrivateKey().PublicKey) suite.signerPrivateKey = GenerateTestPrivateKey() suite.signerAddress = crypto.PubkeyToAddress(suite.signerPrivateKey.PublicKey) suite.recipientAddress = crypto.PubkeyToAddress(GenerateTestPrivateKey().PublicKey) @@ -94,7 +92,7 @@ func (suite *ValidationTestSuite) payment() *Payment { ChannelNonce: big.NewInt(3), MpeContractAddress: suite.mpeContractAddress, } - SignTestPayment(payment, suite.senderPrivateKey) + SignTestPayment(payment, suite.signerPrivateKey) return payment } @@ -125,7 +123,7 @@ func (suite *ValidationTestSuite) TestPaymentIsValid() { func (suite *ValidationTestSuite) TestValidatePaymentChannelNonce() { payment := suite.payment() payment.ChannelNonce = big.NewInt(2) - SignTestPayment(payment, suite.senderPrivateKey) + SignTestPayment(payment, suite.signerPrivateKey) channel := suite.channel() channel.Nonce = big.NewInt(3) @@ -158,7 +156,7 @@ func (suite *ValidationTestSuite) TestValidatePaymentIncorrectSigner() { err := suite.validator.Validate(payment, suite.channel()) - assert.Equal(suite.T(), NewPaymentError(Unauthenticated, "payment is not signed by channel sender"), err) + assert.Equal(suite.T(), NewPaymentError(Unauthenticated, "payment is not signed by channel signer"), err) } func (suite *ValidationTestSuite) TestValidatePaymentChannelCannotGetCurrentBlock() { @@ -200,7 +198,7 @@ func (suite *ValidationTestSuite) TestValidatePaymentChannelExpirationThreshold( func (suite *ValidationTestSuite) TestValidatePaymentAmountIsTooBig() { payment := suite.payment() payment.Amount = big.NewInt(12346) - SignTestPayment(payment, suite.senderPrivateKey) + SignTestPayment(payment, suite.signerPrivateKey) channel := suite.channel() channel.FullAmount = big.NewInt(12345) From 506fbb8f87e960950e73ee823664e7681bde5124 Mon Sep 17 00:00:00 2001 From: Vitaly Bogdanov Date: Mon, 3 Dec 2018 20:28:32 +0300 Subject: [PATCH 3/3] Use channel signer to verify channel state request sender --- escrow/state_service.go | 4 ++-- escrow/state_service_test.go | 13 +++++-------- 2 files changed, 7 insertions(+), 10 deletions(-) diff --git a/escrow/state_service.go b/escrow/state_service.go index 8823093f..2b258005 100644 --- a/escrow/state_service.go +++ b/escrow/state_service.go @@ -47,8 +47,8 @@ func (service *PaymentChannelStateService) GetChannelState(context context.Conte return nil, fmt.Errorf("channel is not found, channelId: %v", channelID) } - if channel.Sender != *sender { - return nil, errors.New("only channel sender can get latest channel state") + if channel.Signer != *sender { + return nil, errors.New("only channel signer can get latest channel state") } if channel.Signature == nil { diff --git a/escrow/state_service_test.go b/escrow/state_service_test.go index 7f31d16e..1ce89663 100644 --- a/escrow/state_service_test.go +++ b/escrow/state_service_test.go @@ -13,7 +13,6 @@ import ( type stateServiceTestType struct { service PaymentChannelStateService - senderPrivateKey *ecdsa.PrivateKey senderAddress common.Address signerPrivateKey *ecdsa.PrivateKey signerAddress common.Address @@ -28,8 +27,7 @@ type stateServiceTestType struct { var stateServiceTest = func() stateServiceTestType { channelServiceMock := &paymentChannelServiceMock{} - senderPrivateKey := GenerateTestPrivateKey() - senderAddress := crypto.PubkeyToAddress(senderPrivateKey.PublicKey) + senderAddress := crypto.PubkeyToAddress(GenerateTestPrivateKey().PublicKey) signerPrivateKey := GenerateTestPrivateKey() signerAddress := crypto.PubkeyToAddress(signerPrivateKey.PublicKey) @@ -43,7 +41,6 @@ var stateServiceTest = func() stateServiceTestType { service: PaymentChannelStateService{ channelService: channelServiceMock, }, - senderPrivateKey: senderPrivateKey, senderAddress: senderAddress, signerPrivateKey: signerPrivateKey, signerAddress: signerAddress, @@ -61,7 +58,7 @@ var stateServiceTest = func() stateServiceTestType { }, defaultRequest: &ChannelStateRequest{ ChannelId: bigIntToBytes(defaultChannelId), - Signature: getSignature(bigIntToBytes(defaultChannelId), senderPrivateKey), + Signature: getSignature(bigIntToBytes(defaultChannelId), signerPrivateKey), }, defaultReply: &ChannelStateReply{ CurrentNonce: bigIntToBytes(big.NewInt(3)), @@ -96,7 +93,7 @@ func TestGetChannelStateChannelIdIsNotPaddedByZero(t *testing.T) { nil, &ChannelStateRequest{ ChannelId: []byte{0xFF}, - Signature: getSignature(bigIntToBytes(channelId), stateServiceTest.senderPrivateKey), + Signature: getSignature(bigIntToBytes(channelId), stateServiceTest.signerPrivateKey), }, ) @@ -135,7 +132,7 @@ func TestGetChannelStateChannelNotFound(t *testing.T) { nil, &ChannelStateRequest{ ChannelId: bigIntToBytes(channelId), - Signature: getSignature(bigIntToBytes(channelId), stateServiceTest.senderPrivateKey), + Signature: getSignature(bigIntToBytes(channelId), stateServiceTest.signerPrivateKey), }, ) @@ -160,7 +157,7 @@ func TestGetChannelStateIncorrectSender(t *testing.T) { }, ) - assert.Equal(t, errors.New("only channel sender can get latest channel state"), err) + assert.Equal(t, errors.New("only channel signer can get latest channel state"), err) assert.Nil(t, reply) }