Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Gettoken for concurrent calls #505

Merged
merged 16 commits into from
Jul 31, 2020
Merged
Show file tree
Hide file tree
Changes from 13 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
95 changes: 91 additions & 4 deletions escrow/memory_storage.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package escrow

import (
"fmt"
"strings"
"sync"
)
Expand Down Expand Up @@ -110,13 +109,101 @@ func (storage *memoryStorage) Clear() (err error) {
}

func (storage *memoryStorage) StartTransaction(conditionKeys []string) (transaction Transaction, err error) {
return nil, fmt.Errorf("Not implemented")
conditionKeyValues := make([]KeyValueData, len(conditionKeys))
for i, key := range conditionKeys {
value, ok, err := storage.Get(key)
if err != nil {
return nil, err
} else if !ok {
conditionKeyValues[i] = KeyValueData{Key: key, Value: "", Present: false}
} else {
conditionKeyValues[i] = KeyValueData{Key: key, Value: value, Present: true}
}

}
transaction = &memoryStorageTransaction{ConditionKeys: conditionKeys, ConditionValues: conditionKeyValues}
return transaction, nil
}

func getValueDataForKey(key string, update []KeyValueData) (data KeyValueData, present bool) {
for _, data := range update {
if strings.Compare(data.Key, key) == 0 {
return data, true
}
}
return data, false
}
func (storage *memoryStorage) CompleteTransaction(transaction Transaction, update []KeyValueData) (ok bool, err error) {
return false, fmt.Errorf("Not implemented")
originalValues := transaction.(*memoryStorageTransaction).ConditionValues
for _, olddata := range originalValues {
if olddata.Present {
//make sure the current value is the same as the value last read
currentValue, _, _ := storage.Get(olddata.Key)
vsbogd marked this conversation as resolved.
Show resolved Hide resolved
if strings.Compare(currentValue, olddata.Value) == 0 {
if updatedData, ok := getValueDataForKey(olddata.Key, update); ok {
if err = storage.Put(updatedData.Key, updatedData.Value); err != nil {
return false, err
}
continue
}
}

} else {
if updatedData, ok := getValueDataForKey(olddata.Key, update); ok {
if ok, err := storage.PutIfAbsent(updatedData.Key, updatedData.Value); err != nil {
return false, err
} else if !ok {
return ok, nil
}
continue
}
}
}
return true, nil
}

func (client *memoryStorage) ExecuteTransaction(request CASRequest) (ok bool, err error) {
return false, fmt.Errorf("Not implemented")

transaction, err := client.StartTransaction(request.ConditionKeys)
anandrgitnirman marked this conversation as resolved.
Show resolved Hide resolved
if err != nil {
return false, err
}
for {
oldvalues, err := transaction.GetConditionValues()
if err != nil {
return false, err
}
newvalues, ok, err := request.Update(oldvalues)
if err != nil {
return false, err
}
ok, err = client.CompleteTransaction(transaction, newvalues)
if err != nil {
return false, err
}
if ok {
return true, nil
}
if request.RetryTillSuccessOrError {
continue
}
}
return true, nil
}

type memoryStorageTransaction struct {
ConditionValues []KeyValueData
ConditionKeys []string
}

func (transaction *memoryStorageTransaction) GetConditionValues() ([]KeyValueData, error) {
values := make([]KeyValueData, len(transaction.ConditionValues))
for i, value := range transaction.ConditionValues {
values[i] = KeyValueData{
Key: value.Key,
Value: value.Value,
Present: value.Present,
}
}
return values, nil
}
3 changes: 3 additions & 0 deletions escrow/prepaid_handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,9 @@ func (h *PrePaidPaymentHandler) Payment(context *handler.GrpcStreamContext) (tra
err *handler.GrpcError) {

prePaidPayment, err := h.getPaymentFromContext(context)
if err != nil {
return nil, err
}
price, priceError := h.PrePaidPaymentValidator.priceStrategy.GetPrice(context)
if priceError != nil {
return nil, paymentErrorToGrpcError(priceError)
Expand Down
9 changes: 2 additions & 7 deletions escrow/prepaid_service.go
Original file line number Diff line number Diff line change
Expand Up @@ -151,13 +151,8 @@ var (
//function and pick it from there
oldState.ChannelID = channelId
newState := oldState.Clone()
//we dont add the old amount planned amont , we just replace it with the latest planned amount signed
newState.UpdateUsageType = PLANNED_AMOUNT
newState.PlannedAmount = revisedAmount
if newState.PlannedAmount.Cmp(oldState.PlannedAmount) < 0 {
return nil, fmt.Errorf("you need to sign for a higher planned amount than %v"+
" on the channel Id %v", oldState.PlannedAmount, oldState.ChannelID)
}
usageKey := &PrePaidDataKey{UsageType: PLANNED_AMOUNT, ChannelID: oldState.ChannelID}
updateDetails(newState, usageKey, revisedAmount)
vsbogd marked this conversation as resolved.
Show resolved Hide resolved
return BuildOldAndNewValuesForCAS(newState)

}
Expand Down
7 changes: 2 additions & 5 deletions escrow/prepaid_service_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -113,12 +113,9 @@ func TestFuncPlannedAmount(t *testing.T) {
Present: true,
}

newValues, err := IncrementPlannedAmount(typedArray, big.NewInt(0), channelId)
assert.Nil(t, newValues)
assert.Equal(t, err.Error(), "you need to sign for a higher planned amount than 3 on the channel Id 10")
newValues, err = IncrementPlannedAmount(typedArray, big.NewInt(4), channelId)
newValues, err := IncrementPlannedAmount(typedArray, big.NewInt(4), channelId)
assert.Nil(t, err)
assert.Equal(t, newValues[0].Value, &PrePaidData{Amount: big.NewInt(4)})
assert.Equal(t, newValues[0].Value, &PrePaidData{Amount: big.NewInt(7)})
}

func TestFuncRefundAmount(t *testing.T) {
Expand Down
159 changes: 159 additions & 0 deletions escrow/token_service.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
//go:generate protoc -I . ./token_service.proto --go_out=plugins=grpc:.
package escrow

import (
"bytes"
"fmt"
"github.com/ethereum/go-ethereum/accounts/abi"
"github.com/singnet/snet-daemon/authutils"
"github.com/singnet/snet-daemon/blockchain"
"github.com/singnet/snet-daemon/token"
"golang.org/x/net/context"
"math/big"
)

type TokenService struct {
channelService PaymentChannelService
prePaidUsageService PrePaidService
tokenManager token.Manager
validator *ChannelPaymentValidator
serviceMetaData blockchain.ServiceMetadata
allowedBlockNumberCheck func(blockNumber *big.Int) (err error)
}

type BlockChainDisabledTokenService struct {
}

func (service BlockChainDisabledTokenService) GetToken(ctx context.Context, request *TokenRequest) (reply *TokenReply, err error) {
return &TokenReply{}, nil
}

func NewTokenService(paymentChannelService PaymentChannelService,
usageService PrePaidService, tokenManager token.Manager, validator *ChannelPaymentValidator, metadata *blockchain.ServiceMetadata) *TokenService {

return &TokenService{
channelService: paymentChannelService,
prePaidUsageService: usageService,
tokenManager: tokenManager,
validator: validator,
serviceMetaData: *metadata,
allowedBlockNumberCheck: func(blockNumber *big.Int) error {
currentBlockNumber, err := validator.currentBlock()
if err != nil {
return err
}
differenceInBlockNumber := blockNumber.Sub(blockNumber, currentBlockNumber)
if differenceInBlockNumber.Abs(differenceInBlockNumber).Uint64() > authutils.AllowedBlockChainDifference {
return fmt.Errorf("authentication failed as the signature passed has expired")
}
return nil
},
}
}

func (service *TokenService) verifySignatureAndSignedAmountEligibility(channelId *big.Int,
latestAuthorizedAmount *big.Int, request *TokenRequest) (err error) {
channel, ok, err := service.channelService.PaymentChannel(&PaymentChannelKey{ID: channelId})

if !ok {
return fmt.Errorf("channel is not found, channelId: %v", channelId)
}
if err != nil {
return fmt.Errorf("error:%v was seen on retreiving details of channelID:%v",
err.Error(), channelId)
}
if channel.AuthorizedAmount.Cmp(latestAuthorizedAmount) > 0 {
vsbogd marked this conversation as resolved.
Show resolved Hide resolved
return fmt.Errorf("signed amount for token request needs to be greater than last signed amount")
}
if channel.FullAmount.Cmp(latestAuthorizedAmount) < 0 {
return fmt.Errorf("signed amount for token request cannot be greater than full amount in channel")
}
//verify signature
if err = service.verifySignature(request, channel); err != nil {
return err
}
payment := service.getPayment(channelId, latestAuthorizedAmount, request)
if err = service.validator.Validate(payment, channel); err != nil {
return err
}
//update the channel Signature if you have a new Signed Amount received
if latestAuthorizedAmount.Cmp(channel.AuthorizedAmount) > 0 {
transaction, err := service.channelService.StartPaymentTransaction(payment)
if err != nil {
return err
}
if err = transaction.Commit(); err != nil {
return err
}
if err = service.prePaidUsageService.UpdateUsage(channelId, latestAuthorizedAmount.Sub(latestAuthorizedAmount, channel.AuthorizedAmount), PLANNED_AMOUNT); err != nil {
return err
}
}

return nil
}

func (service *TokenService) getPayment(channelId *big.Int, latestAuthorizedAmount *big.Int, request *TokenRequest) *Payment {

return &Payment{
MpeContractAddress: service.serviceMetaData.GetMpeAddress(),
ChannelID: channelId,
ChannelNonce: big.NewInt(0).SetUint64(request.CurrentNonce),
Amount: latestAuthorizedAmount,
Signature: request.ClaimSignature,
}
}

func (service *TokenService) verifySignature(request *TokenRequest, channel *PaymentChannelData) (err error) {
message := bytes.Join([][]byte{
request.GetClaimSignature(),
abi.U256(big.NewInt(int64(request.CurrentBlock))),
}, nil)
signature := request.GetSignature()

sender, err := authutils.GetSignerAddressFromMessage(message, signature)
if err != nil {
return fmt.Errorf("incorrect signature")
}

if channel.Signer != *sender && *sender != channel.Sender && *sender != channel.Recipient {
return fmt.Errorf("only channel signer/sender/receiver can get a Valid Token")
}

if err = service.allowedBlockNumberCheck(big.NewInt(0).SetUint64(request.CurrentBlock)); err != nil {
return err
}
return nil
}
func (service *TokenService) GetToken(ctx context.Context, request *TokenRequest) (reply *TokenReply, err error) {

//Check for update state
channelID := big.NewInt(0).SetUint64(request.ChannelId)
latestAuthorizedAmount := big.NewInt(0).SetUint64(request.SignedAmount)

if err = service.verifySignatureAndSignedAmountEligibility(channelID, latestAuthorizedAmount, request); err != nil {
return nil, err
}

usage, ok, err := service.prePaidUsageService.GetUsage(PrePaidDataKey{ChannelID: channelID, UsageType: USED_AMOUNT})
usageAmount := big.NewInt(0)
if ok {
usageAmount = usage.Amount
}
if err != nil {
return nil, err
}

plannedAmount, ok, err := service.prePaidUsageService.GetUsage(PrePaidDataKey{ChannelID: channelID, UsageType: PLANNED_AMOUNT})

if !ok {
return nil, fmt.Errorf("Unable to retrieve planned Amount ")
}
if err != nil {
return nil, err
}
tokenGenerated, err := service.tokenManager.CreateToken(channelID)
tokenBytes := []byte(fmt.Sprintf("%v", tokenGenerated))
return &TokenReply{ChannelId: request.ChannelId, Token: tokenBytes, PlannedAmount: plannedAmount.Amount.Uint64(),
UsedAmount: usageAmount.Uint64()}, nil
}
2 changes: 2 additions & 0 deletions escrow/token_service.proto
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ message TokenRequest {
//current block number (signature will be valid only for short time around this block number)
uint64 current_block = 5;

bytes claim_signature = 6;

}

// TokenReply message contains a latest channel state. current_nonce and
Expand Down
Loading