From 5bd2c49130639f38dafc054419b07f7a9891b808 Mon Sep 17 00:00:00 2001 From: anandrgitnirman Date: Fri, 7 Aug 2020 21:08:32 +0530 Subject: [PATCH 1/5] #509 - Remove the deserialization method , change the contract to pass a string and get a type , so that we still support the use case where we need to store objects as keys and Values ( ex concurrency) --- escrow/atomic_storage.go | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/escrow/atomic_storage.go b/escrow/atomic_storage.go index 3ca588f0..2c34c70e 100644 --- a/escrow/atomic_storage.go +++ b/escrow/atomic_storage.go @@ -207,7 +207,7 @@ type TypedKeyValueData struct { type TypedAtomicStorageImpl struct { atomicStorage AtomicStorage keySerializer func(key interface{}) (serialized string, err error) - keyDeserializer func(serialized string, key interface{}) (err error) + keyDeserializer func(serialized string) (key interface{}, err error) keyType reflect.Type valueSerializer func(value interface{}) (serialized string, err error) valueDeserializer func(serialized string, value interface{}) (err error) @@ -237,15 +237,6 @@ func (storage *TypedAtomicStorageImpl) Get(key interface{}) (value interface{}, return value, true, nil } -func (storage *TypedAtomicStorageImpl) deserializeKey(keyString string) (key interface{}, err error) { - key = reflect.New(storage.keyType).Interface() - err = storage.keyDeserializer(keyString, key) - if err != nil { - return nil, err - } - return key, err -} - func (storage *TypedAtomicStorageImpl) deserializeValue(valueString string) (value interface{}, err error) { value = reflect.New(storage.valueType).Interface() err = storage.valueDeserializer(valueString, value) @@ -355,7 +346,7 @@ func (storage *TypedAtomicStorageImpl) convertKeyValueDataToTyped(keyValueData [ result[i] = TypedKeyValueData{ Present: keyValueString.Present, } - result[i].Key, err = storage.deserializeKey(keyValueString.Key) + result[i].Key, err = storage.keyDeserializer(keyValueString.Key) if err != nil { return nil, err } From b3bd8751b3a8e1c641a950aa9ea5cb673c06d40a Mon Sep 17 00:00:00 2001 From: anandrgitnirman Date: Fri, 7 Aug 2020 21:11:49 +0530 Subject: [PATCH 2/5] #509- Remove the unwanted de serialization initialization , and use a custom key generation --- escrow/payment_channel_storage.go | 6 ++++-- escrow/payment_storage.go | 3 +-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/escrow/payment_channel_storage.go b/escrow/payment_channel_storage.go index 88ef6c8b..a77ababf 100644 --- a/escrow/payment_channel_storage.go +++ b/escrow/payment_channel_storage.go @@ -25,8 +25,7 @@ func NewPaymentChannelStorage(atomicStorage AtomicStorage) *PaymentChannelStorag return &PaymentChannelStorage{ delegate: &TypedAtomicStorageImpl{ atomicStorage: NewPrefixedAtomicStorage(atomicStorage, "/payment-channel/storage"), - keySerializer: serialize, - keyDeserializer: deserialize, + keySerializer: serializeKey, keyType: reflect.TypeOf(PaymentChannelKey{}), valueSerializer: serialize, valueDeserializer: deserialize, @@ -35,6 +34,9 @@ func NewPaymentChannelStorage(atomicStorage AtomicStorage) *PaymentChannelStorag } } +func serializeKey(key interface{}) (slice string, err error) { + return fmt.Sprintf("%v", key), nil +} func serialize(value interface{}) (slice string, err error) { var b bytes.Buffer e := gob.NewEncoder(&b) diff --git a/escrow/payment_storage.go b/escrow/payment_storage.go index 6b539757..56252bac 100644 --- a/escrow/payment_storage.go +++ b/escrow/payment_storage.go @@ -17,8 +17,7 @@ func NewPaymentStorage(atomicStorage AtomicStorage) *PaymentStorage { delegate: &TypedAtomicStorageImpl{ atomicStorage: NewPrefixedAtomicStorage(atomicStorage, "/payment/storage"), - keySerializer: serialize, - keyDeserializer: deserialize, + keySerializer: serializeKey, keyType: reflect.TypeOf(""), valueSerializer: serialize, valueDeserializer: deserialize, From ac649de110c9c5ca530bb53f44c0f854f150b942 Mon Sep 17 00:00:00 2001 From: anandrgitnirman Date: Fri, 7 Aug 2020 21:12:34 +0530 Subject: [PATCH 3/5] #509 - Use the custom made key for Free calls storage --- escrow/free_call_storage.go | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/escrow/free_call_storage.go b/escrow/free_call_storage.go index cc0b0ddf..45698df9 100644 --- a/escrow/free_call_storage.go +++ b/escrow/free_call_storage.go @@ -15,8 +15,7 @@ func NewFreeCallUserStorage(atomicStorage AtomicStorage) *FreeCallUserStorage { delegate: atomicStorage, keyPrefix: "/free-call-user/storage", }, - keySerializer: serialize, - keyDeserializer: deserialize, + keySerializer: serializeFreeCallKey, keyType: reflect.TypeOf(FreeCallUserKey{}), valueSerializer: serialize, valueDeserializer: deserialize, @@ -25,6 +24,10 @@ func NewFreeCallUserStorage(atomicStorage AtomicStorage) *FreeCallUserStorage { } } +func serializeFreeCallKey(key interface{}) (serialized string, err error) { + myKey := key.(*FreeCallUserKey) + return myKey.String(), nil +} func (storage *FreeCallUserStorage) Get(key *FreeCallUserKey) (state *FreeCallUserData, ok bool, err error) { value, ok, err := storage.delegate.Get(key) if err != nil || !ok { From d8432e9f5b7cf815fc407a17fae2adce8a57a26d Mon Sep 17 00:00:00 2001 From: anandrgitnirman Date: Fri, 7 Aug 2020 21:13:38 +0530 Subject: [PATCH 4/5] #509 - Use custom key serialization and also de serialization for pre paid ( concurrent calls) --- escrow/prepaid_service.go | 12 ++++++------ escrow/prepaid_service_test.go | 26 +++++++++++++++++--------- escrow/prepaid_storage.go | 27 ++++++++++++++++++++++++--- 3 files changed, 47 insertions(+), 18 deletions(-) diff --git a/escrow/prepaid_service.go b/escrow/prepaid_service.go index b78258b7..7a105667 100644 --- a/escrow/prepaid_service.go +++ b/escrow/prepaid_service.go @@ -91,7 +91,7 @@ func convertTypedDataToPrePaidUsage(data []TypedKeyValueData) (new *PrePaidUsage usageData := &PrePaidUsageData{PlannedAmount: big.NewInt(0), UsedAmount: big.NewInt(0), RefundAmount: big.NewInt(0)} for _, usageType := range data { - key := usageType.Key.(*PrePaidDataKey) + key := usageType.Key.(PrePaidDataKey) usageData.ChannelID = key.ChannelID if !usageType.Present { continue @@ -112,7 +112,7 @@ func convertTypedDataToPrePaidUsage(data []TypedKeyValueData) (new *PrePaidUsage func BuildOldAndNewValuesForCAS(data *PrePaidUsageData) (newValues []TypedKeyValueData, err error) { updateUsageData := &PrePaidData{} - updateUsageKey := &PrePaidDataKey{ChannelID: data.ChannelID, UsageType: data.UpdateUsageType} + updateUsageKey := PrePaidDataKey{ChannelID: data.ChannelID, UsageType: data.UpdateUsageType} if amt, err := data.GetAmountForUsageType(); err != nil { return nil, err } else { @@ -133,7 +133,7 @@ var ( } oldState.ChannelID = channelId newState := oldState.Clone() - usageKey := &PrePaidDataKey{UsageType: USED_AMOUNT, ChannelID: oldState.ChannelID} + usageKey := PrePaidDataKey{UsageType: USED_AMOUNT, ChannelID: oldState.ChannelID} updateDetails(newState, usageKey, revisedAmount) if newState.UsedAmount.Cmp(oldState.PlannedAmount.Add(oldState.PlannedAmount, oldState.RefundAmount)) > 0 { return nil, fmt.Errorf("Usage Exceeded on channel Id %v", oldState.ChannelID) @@ -151,7 +151,7 @@ var ( //function and pick it from there oldState.ChannelID = channelId newState := oldState.Clone() - usageKey := &PrePaidDataKey{UsageType: PLANNED_AMOUNT, ChannelID: oldState.ChannelID} + usageKey := PrePaidDataKey{UsageType: PLANNED_AMOUNT, ChannelID: oldState.ChannelID} updateDetails(newState, usageKey, revisedAmount) return BuildOldAndNewValuesForCAS(newState) @@ -163,14 +163,14 @@ var ( return nil, err } newState.ChannelID = channelId - usageKey := &PrePaidDataKey{UsageType: REFUND_AMOUNT, ChannelID: newState.ChannelID} + usageKey := PrePaidDataKey{UsageType: REFUND_AMOUNT, ChannelID: newState.ChannelID} updateDetails(newState, usageKey, revisedAmount) return BuildOldAndNewValuesForCAS(newState) } ) -func updateDetails(usageData *PrePaidUsageData, key *PrePaidDataKey, usage *big.Int) { +func updateDetails(usageData *PrePaidUsageData, key PrePaidDataKey, usage *big.Int) { usageData.ChannelID = key.ChannelID usageData.UpdateUsageType = key.UsageType switch key.UsageType { diff --git a/escrow/prepaid_service_test.go b/escrow/prepaid_service_test.go index a0404965..5b09d86b 100644 --- a/escrow/prepaid_service_test.go +++ b/escrow/prepaid_service_test.go @@ -31,18 +31,18 @@ func Test_getAllKeys(t *testing.T) { func Test_convertTypedDataToPrePaidUsage(t *testing.T) { typedArray := make([]TypedKeyValueData, 3) typedArray[0] = TypedKeyValueData{ - Key: &PrePaidDataKey{ChannelID: big.NewInt(10), UsageType: USED_AMOUNT}, + Key: PrePaidDataKey{ChannelID: big.NewInt(10), UsageType: USED_AMOUNT}, Value: &PrePaidData{Amount: big.NewInt(3)}, Present: true, } typedArray[1] = TypedKeyValueData{ - Key: &PrePaidDataKey{ChannelID: big.NewInt(10), UsageType: PLANNED_AMOUNT}, + Key: PrePaidDataKey{ChannelID: big.NewInt(10), UsageType: PLANNED_AMOUNT}, Value: &PrePaidData{Amount: big.NewInt(10)}, Present: true, } typedArray[2] = TypedKeyValueData{ - Key: &PrePaidDataKey{ChannelID: big.NewInt(10), UsageType: REFUND_AMOUNT}, + Key: PrePaidDataKey{ChannelID: big.NewInt(10), UsageType: REFUND_AMOUNT}, Value: &PrePaidData{Amount: big.NewInt(4)}, Present: true, } @@ -53,7 +53,7 @@ func Test_convertTypedDataToPrePaidUsage(t *testing.T) { assert.Equal(t, newState.RefundAmount, big.NewInt(4)) typedArray[0] = TypedKeyValueData{ - Key: &PrePaidDataKey{ChannelID: big.NewInt(10), UsageType: "BAD"}, + Key: PrePaidDataKey{ChannelID: big.NewInt(10), UsageType: "BAD"}, Value: &PrePaidData{Amount: big.NewInt(3)}, Present: true, } @@ -78,21 +78,29 @@ func TestBuildOldAndNewValuesForCAS(t *testing.T) { func Test_updateDetails(t *testing.T) { usage := &PrePaidUsageData{PlannedAmount: big.NewInt(10), UpdateUsageType: PLANNED_AMOUNT} - updateDetails(usage, &PrePaidDataKey{ChannelID: big.NewInt(11), UsageType: PLANNED_AMOUNT}, big.NewInt(10)) + updateDetails(usage, PrePaidDataKey{ChannelID: big.NewInt(11), UsageType: PLANNED_AMOUNT}, big.NewInt(10)) assert.Equal(t, usage.PlannedAmount, big.NewInt(20)) } +func Test_KeySerializeAndDeserialize(t *testing.T) { + key := PrePaidDataKey{ChannelID: big.NewInt(11), UsageType: PLANNED_AMOUNT} + newkey, err := serializePrePaidKey(key) + assert.Equal(t, "{ID:11/P}", newkey) + assert.Nil(t, err) + +} + func TestFuncUsedAmount(t *testing.T) { channelId := big.NewInt(10) typedArray := make([]TypedKeyValueData, 2) typedArray[0] = TypedKeyValueData{ - Key: &PrePaidDataKey{ChannelID: channelId, UsageType: USED_AMOUNT}, + Key: PrePaidDataKey{ChannelID: channelId, UsageType: USED_AMOUNT}, Value: &PrePaidData{Amount: big.NewInt(3)}, Present: true, } typedArray[1] = TypedKeyValueData{ - Key: &PrePaidDataKey{ChannelID: channelId, UsageType: PLANNED_AMOUNT}, + Key: PrePaidDataKey{ChannelID: channelId, UsageType: PLANNED_AMOUNT}, Value: &PrePaidData{Amount: big.NewInt(30)}, Present: true, } @@ -108,7 +116,7 @@ func TestFuncPlannedAmount(t *testing.T) { channelId := big.NewInt(10) typedArray := make([]TypedKeyValueData, 1) typedArray[0] = TypedKeyValueData{ - Key: &PrePaidDataKey{ChannelID: channelId, UsageType: PLANNED_AMOUNT}, + Key: PrePaidDataKey{ChannelID: channelId, UsageType: PLANNED_AMOUNT}, Value: &PrePaidData{Amount: big.NewInt(3)}, Present: true, } @@ -122,7 +130,7 @@ func TestFuncRefundAmount(t *testing.T) { channelId := big.NewInt(10) typedArray := make([]TypedKeyValueData, 1) typedArray[0] = TypedKeyValueData{ - Key: &PrePaidDataKey{ChannelID: channelId, UsageType: REFUND_AMOUNT}, + Key: PrePaidDataKey{ChannelID: channelId, UsageType: REFUND_AMOUNT}, Value: &PrePaidData{Amount: big.NewInt(3)}, Present: true, } diff --git a/escrow/prepaid_storage.go b/escrow/prepaid_storage.go index d1767546..c3253123 100644 --- a/escrow/prepaid_storage.go +++ b/escrow/prepaid_storage.go @@ -4,6 +4,7 @@ import ( "fmt" "math/big" "reflect" + "strings" ) // To Support PrePaid calls and also concurrency @@ -34,7 +35,7 @@ func (data *PrePaidData) String() string { return fmt.Sprintf("{Amount:%v}", data.Amount) } func (key *PrePaidDataKey) String() string { - return fmt.Sprintf("{ChannelID:%v,UsageType:%v}", key.ChannelID, key.UsageType) + return fmt.Sprintf("{ID:%v/%v}", key.ChannelID, key.UsageType) } const ( @@ -79,12 +80,32 @@ func (data PrePaidUsageData) Clone() *PrePaidUsageData { } } +func serializePrePaidKey(key interface{}) (serialized string, err error) { + myKey := key.(PrePaidDataKey) + return myKey.String(), nil +} + +func deserializePrePaidKey(keyString string) (key interface{}, err error) { + keyString = strings.Replace(keyString, "{ID:", "", -1) + keyString = strings.Replace(keyString, "}", "", -1) + keydetails := strings.Split(keyString, "/") + prePaidKey := PrePaidDataKey{} + + channeId, ok := big.NewInt(0).SetString(keydetails[0], 10) + if !ok { + return nil, fmt.Errorf("not a valid number") + } + prePaidKey.ChannelID = channeId + prePaidKey.UsageType = keydetails[1] + return prePaidKey, nil +} + // NewPrepaidStorage returns new instance of TypedAtomicStorage func NewPrepaidStorage(atomicStorage AtomicStorage) TypedAtomicStorage { return &TypedAtomicStorageImpl{ atomicStorage: NewPrefixedAtomicStorage(atomicStorage, "/PrePaid/storage"), - keySerializer: serialize, - keyDeserializer: deserialize, + keySerializer: serializePrePaidKey, + keyDeserializer: deserializePrePaidKey, keyType: reflect.TypeOf(PrePaidDataKey{}), valueSerializer: serialize, valueDeserializer: deserialize, From a4c9a0c33fc416097bb97340b012fe49ac75ccd3 Mon Sep 17 00:00:00 2001 From: Vitaly Bogdanov Date: Fri, 7 Aug 2020 20:07:24 +0300 Subject: [PATCH 5/5] Remove keyDeserializer --- escrow/atomic_storage.go | 64 +++++++++++++++------------------------ escrow/prepaid_storage.go | 17 ----------- 2 files changed, 24 insertions(+), 57 deletions(-) diff --git a/escrow/atomic_storage.go b/escrow/atomic_storage.go index 2c34c70e..c8e292e1 100644 --- a/escrow/atomic_storage.go +++ b/escrow/atomic_storage.go @@ -207,7 +207,6 @@ type TypedKeyValueData struct { type TypedAtomicStorageImpl struct { atomicStorage AtomicStorage keySerializer func(key interface{}) (serialized string, err error) - keyDeserializer func(serialized string) (key interface{}, err error) keyType reflect.Type valueSerializer func(value interface{}) (serialized string, err error) valueDeserializer func(serialized string, value interface{}) (err error) @@ -327,29 +326,23 @@ func (storage *TypedAtomicStorageImpl) Delete(key interface{}) (err error) { return storage.atomicStorage.Delete(keyString) } -type typedTransactionImpl struct { - transactionString Transaction - storage *TypedAtomicStorageImpl -} - -func (transaction *typedTransactionImpl) GetConditionValues() ([]TypedKeyValueData, error) { - keyValueDataString, err := transaction.transactionString.GetConditionValues() - if err != nil { - return nil, err - } - return transaction.storage.convertKeyValueDataToTyped(keyValueDataString) -} - -func (storage *TypedAtomicStorageImpl) convertKeyValueDataToTyped(keyValueData []KeyValueData) (result []TypedKeyValueData, err error) { - result = make([]TypedKeyValueData, len(keyValueData)) - for i, keyValueString := range keyValueData { - result[i] = TypedKeyValueData{ - Present: keyValueString.Present, - } - result[i].Key, err = storage.keyDeserializer(keyValueString.Key) +func (storage *TypedAtomicStorageImpl) convertKeyValueDataToTyped(conditionKeys []interface{}, keyValueData []KeyValueData) (result []TypedKeyValueData, err error) { + result = make([]TypedKeyValueData, len(conditionKeys)) + for i, conditionKey := range conditionKeys { + conditionKeyString, err := storage.keySerializer(conditionKey) if err != nil { return nil, err } + result[i] = TypedKeyValueData{ + Key: conditionKey, + Present: false, + } + keyValueString, ok := findKeyValueByKey(keyValueData, conditionKeyString) + if ok { + result[i].Present = keyValueString.Present + } else { + result[i].Present = false + } if !keyValueString.Present { continue } @@ -361,10 +354,19 @@ func (storage *TypedAtomicStorageImpl) convertKeyValueDataToTyped(keyValueData [ return result, nil } +func findKeyValueByKey(keyValueData []KeyValueData, key string) (keyValueString *KeyValueData, ok bool) { + for _, keyValueString := range keyValueData { + if keyValueString.Key == key { + return &keyValueString, true + } + } + return nil, false +} + func (storage *TypedAtomicStorageImpl) ExecuteTransaction(request TypedCASRequest) (ok bool, err error) { updateFunction := func(conditionValues []KeyValueData) (update []KeyValueData, ok bool, err error) { - typedValues, err := storage.convertKeyValueDataToTyped(conditionValues) + typedValues, err := storage.convertKeyValueDataToTyped(request.ConditionKeys, conditionValues) if err != nil { return nil, false, err } @@ -397,17 +399,6 @@ func (storage *TypedAtomicStorageImpl) convertTypedKeyToString(typedKeys []inter } return stringKeys, nil } -func (storage *TypedAtomicStorageImpl) StartTransaction(conditionKeys []string) (transaction TypedTransaction, err error) { - transactionString, err := storage.atomicStorage.StartTransaction(conditionKeys) - if err != nil { - return - } - - return &typedTransactionImpl{ - transactionString: transactionString, - storage: storage, - }, nil -} func (storage *TypedAtomicStorageImpl) convertTypedKeyValueDataToString( update []TypedKeyValueData) (data []KeyValueData, err error) { @@ -433,10 +424,3 @@ func (storage *TypedAtomicStorageImpl) convertTypedKeyValueDataToString( } return updateString, nil } -func (storage *TypedAtomicStorageImpl) CompleteTransaction(transaction TypedTransaction, update []TypedKeyValueData) (ok bool, err error) { - updateString, err := storage.convertTypedKeyValueDataToString(update) - if err != nil { - return false, err - } - return storage.atomicStorage.CompleteTransaction(transaction.(*typedTransactionImpl).transactionString, updateString) -} diff --git a/escrow/prepaid_storage.go b/escrow/prepaid_storage.go index c3253123..e8d59991 100644 --- a/escrow/prepaid_storage.go +++ b/escrow/prepaid_storage.go @@ -4,7 +4,6 @@ import ( "fmt" "math/big" "reflect" - "strings" ) // To Support PrePaid calls and also concurrency @@ -85,27 +84,11 @@ func serializePrePaidKey(key interface{}) (serialized string, err error) { return myKey.String(), nil } -func deserializePrePaidKey(keyString string) (key interface{}, err error) { - keyString = strings.Replace(keyString, "{ID:", "", -1) - keyString = strings.Replace(keyString, "}", "", -1) - keydetails := strings.Split(keyString, "/") - prePaidKey := PrePaidDataKey{} - - channeId, ok := big.NewInt(0).SetString(keydetails[0], 10) - if !ok { - return nil, fmt.Errorf("not a valid number") - } - prePaidKey.ChannelID = channeId - prePaidKey.UsageType = keydetails[1] - return prePaidKey, nil -} - // NewPrepaidStorage returns new instance of TypedAtomicStorage func NewPrepaidStorage(atomicStorage AtomicStorage) TypedAtomicStorage { return &TypedAtomicStorageImpl{ atomicStorage: NewPrefixedAtomicStorage(atomicStorage, "/PrePaid/storage"), keySerializer: serializePrePaidKey, - keyDeserializer: deserializePrePaidKey, keyType: reflect.TypeOf(PrePaidDataKey{}), valueSerializer: serialize, valueDeserializer: deserialize,