Skip to content

Commit

Permalink
Improvement token and patch envelope (#35)
Browse files Browse the repository at this point in the history
* Change settings for json serializer
* Add LockBatch and GetUTXO
* Do not check the sig for Init method
* Resolve the unclear json serialization
  • Loading branch information
olaeseane authored Aug 14, 2023
1 parent e038aad commit 65a82cf
Show file tree
Hide file tree
Showing 7 changed files with 197 additions and 27 deletions.
35 changes: 20 additions & 15 deletions extensions/envelope/middleware.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,31 +18,34 @@ const (

nonceObjectType = "nonce"
invokeType = "invoke"
initType = "init"

TimeLayout = "2006-01-02T15:04:05.000Z"

PubKey string = "envelopePubkey" // router context key
)

// middleware for checking signature that is got in envelop
// Verify is a middleware for checking signature in envelop
func Verify() router.MiddlewareFunc {
return func(next router.HandlerFunc, pos ...int) router.HandlerFunc {
return func(c router.Context) (interface{}, error) {
if c.Handler().Type == invokeType {
iArgs := c.GetArgs()
if len(iArgs) == 2 {
c.Logger().Sugar().Error(ErrSignatureNotFound)
return nil, ErrSignatureNotFound
} else {
var (
e *Envelope
err error
)
if e, err = verifyEnvelope(c, iArgs[methodNamePos], iArgs[payloadPos], iArgs[envelopePos]); err != nil {
return nil, err
if string(iArgs[methodNamePos]) != initType {
if len(iArgs) == 2 {
c.Logger().Sugar().Error(ErrSignatureNotFound)
return nil, ErrSignatureNotFound
} else {
var (
e *Envelope
err error
)
if e, err = verifyEnvelope(c, iArgs[methodNamePos], iArgs[payloadPos], iArgs[envelopePos]); err != nil {
return nil, err
}
// store correct pubkey in context
c.SetParam(PubKey, e.PublicKey)
}
// store corect pubkey in context
c.SetParam(PubKey, e.PublicKey)
}
}
return next(c)
Expand All @@ -58,6 +61,7 @@ func verifyEnvelope(c router.Context, method, payload, envlp []byte) (*Envelope,
return nil, err
}
envelope := data.(*Envelope)

if envelope.Deadline.AsTime().Unix() != 0 {
if envelope.Deadline.AsTime().Unix() < time.Now().Unix() {
c.Logger().Sugar().Error(ErrDeadlineExpired)
Expand All @@ -70,7 +74,7 @@ func verifyEnvelope(c router.Context, method, payload, envlp []byte) (*Envelope,
c.Logger().Sugar().Error(ErrInvalidMethod)
return nil, ErrInvalidMethod
}
if string(c.Stub().GetChannelID()) != envelope.Channel {
if c.Stub().GetChannelID() != envelope.Channel {
c.Logger().Sugar().Error(ErrInvalidChannel)
return nil, ErrInvalidChannel
}
Expand All @@ -95,7 +99,8 @@ func verifyEnvelope(c router.Context, method, payload, envlp []byte) (*Envelope,
deadline = envelope.Deadline.AsTime().Format(TimeLayout)
}
if err := CheckSig(payload, envelope.Nonce, envelope.Channel, envelope.Chaincode, envelope.Method, deadline, pubkey, sig); err != nil {
c.Logger().Sugar().Error(ErrCheckSignatureFailed)
c.Logger().Error(ErrCheckSignatureFailed.Error(), zap.String("payload", string(payload)), zap.Any("envelope", envelope))
//c.Logger().Sugar().Error(ErrCheckSignatureFailed)
return nil, ErrCheckSignatureFailed
}
} else {
Expand Down
10 changes: 6 additions & 4 deletions extensions/envelope/signature.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,18 +37,20 @@ func Hash(payload []byte, nonce, channel, chaincode, method, deadline string, pu
func CreateSig(payload []byte, nonce, channel, chaincode, method, deadline string, privateKey []byte) ([]byte, []byte) {
pubKey := ed25519.PrivateKey(privateKey).Public()
hashed := Hash(payload, nonce, channel, chaincode, method, deadline, []byte(pubKey.(ed25519.PublicKey)))
sig := ed25519.Sign(ed25519.PrivateKey(privateKey), hashed[:])
return []byte(pubKey.(ed25519.PublicKey)), sig
sig := ed25519.Sign(privateKey, hashed[:])
return pubKey.(ed25519.PublicKey), sig
}

func CheckSig(payload []byte, nonce, channel, chaincode, method, deadline string, pubKey []byte, sig []byte) error {
hashed := Hash(payload, nonce, channel, chaincode, method, deadline, pubKey)
if !ed25519.Verify(ed25519.PublicKey(pubKey), hashed[:], sig) {
if !ed25519.Verify(pubKey, hashed[:], sig) {
return ErrCheckSignatureFailed
}
return nil
}

func removeSpacesBetweenCommaAndQuotes(s []byte) []byte {
return []byte(strings.ReplaceAll(string(s), `", "`, `","`))
removed := strings.ReplaceAll(string(s), `", "`, `","`)
removed = strings.ReplaceAll(removed, `"}, {"`, `"},{"`)
return []byte(strings.ReplaceAll(removed, `], "`, `],"`))
}
8 changes: 8 additions & 0 deletions extensions/token/balance_account.go
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,10 @@ func (s *AccountStore) Lock(ctx router.Context, burn *BalanceOperation) (*LockId
return nil, nil
}

func (u *AccountStore) LockBatch(ctx router.Context, ops []*BalanceOperation) ([]*LockId, error) {
return nil, nil
}

func (s *AccountStore) Unlock(ctx router.Context, id *LockId) error {
return nil
}
Expand All @@ -119,6 +123,10 @@ func (s *AccountStore) BurnLock(ctx router.Context, id *LockId) error {
return nil
}

func (s *AccountStore) GetUTXO(ctx router.Context, utxoId *UTXOId) (*UTXO, error) {
return nil, nil
}

// todo: add TransferLock implementation
func (u *AccountStore) TransferLock(ctx router.Context, id *LockId, transfer *TransferOperation) error {
return nil
Expand Down
2 changes: 2 additions & 0 deletions extensions/token/balance_store.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,14 @@ type (
BalanceStore interface {
Get(router.Context, *BalanceId) (*Balance, error)
GetLocked(router.Context, *BalanceId) (*Balance, error)
GetUTXO(router.Context, *UTXOId) (*UTXO, error)
List(router.Context, *TokenId) ([]*Balance, error)
Transfer(router.Context, *TransferOperation) error
TransferBatch(router.Context, []*TransferOperation) error
Mint(router.Context, *BalanceOperation) error
Burn(router.Context, *BalanceOperation) error
Lock(router.Context, *BalanceOperation) (*LockId, error)
LockBatch(router.Context, []*BalanceOperation) ([]*LockId, error)
Unlock(router.Context, *LockId) error
BurnLock(router.Context, *LockId) error
TransferLock(router.Context, *LockId, *TransferOperation) error
Expand Down
134 changes: 127 additions & 7 deletions extensions/token/balance_utxo.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package token

import (
"errors"
"fmt"
"math/big"
"strings"

Expand All @@ -15,6 +16,7 @@ var _ BalanceStore = &UTXOStore{}
var (
ErrSenderRecipientEqual = errors.New(`sender recipient equal`)
ErrSenderNotEqual = errors.New(`sender not equal`)
ErrOpAddressNotEqual = errors.New(`operation address not equal`)
ErrSymbolNotEqual = errors.New(`symbol not equal`)
ErrRecipientDuplicate = errors.New(`errors recipient duplicate`)
)
Expand Down Expand Up @@ -96,6 +98,14 @@ func (u *UTXOStore) GetLocked(ctx router.Context, balanceId *BalanceId) (*Balanc
return balance, nil
}

func (u *UTXOStore) GetUTXO(ctx router.Context, utxoId *UTXOId) (*UTXO, error) {
utxo, err := State(ctx).Get(&UTXOId{Symbol: utxoId.Symbol, Group: utxoId.Group, Address: utxoId.Address, TxId: utxoId.TxId}, &UTXO{})
if err != nil {
return nil, err
}
return utxo.(*UTXO), nil
}

// ListOutputs unspended outputs list
func (u *UTXOStore) ListOutputs(ctx router.Context, balanceId *BalanceId) ([]*UTXO, error) {
return listOutputs(ctx, balanceId)
Expand Down Expand Up @@ -154,7 +164,7 @@ func (u *UTXOStore) Transfer(ctx router.Context, transfer *TransferOperation) er
Group: strings.Join(transfer.Group, `,`),
Address: transfer.Sender,
TxId: txID,
Amount: decimal.BigIntSubAsDecimal(outputsAmount, transferAmount),
Amount: decimal.BigIntSubAsDecimal(outputsAmount, transferAmount, transfer.Amount.Scale),
Locked: false,
}
if err := State(ctx).Insert(senderChangeOutput); err != nil {
Expand All @@ -174,6 +184,7 @@ func (u *UTXOStore) Transfer(ctx router.Context, transfer *TransferOperation) er
func (u *UTXOStore) TransferBatch(ctx router.Context, transfers []*TransferOperation) error {
var (
sender, symbol string
scale int32
group []string
recipients = make(map[string]interface{})
totalAmount = big.NewInt(0)
Expand Down Expand Up @@ -207,6 +218,8 @@ func (u *UTXOStore) TransferBatch(ctx router.Context, transfers []*TransferOpera
panic(`implement me`)
}

scale = transfer.Amount.Scale

if _, ok := recipients[transfer.Recipient]; ok {
return ErrRecipientDuplicate
}
Expand Down Expand Up @@ -262,7 +275,7 @@ func (u *UTXOStore) TransferBatch(ctx router.Context, transfers []*TransferOpera
Group: strings.Join(group, `,`),
Address: sender,
TxId: txID,
Amount: decimal.BigIntSubAsDecimal(outputsAmount, totalAmount),
Amount: decimal.BigIntSubAsDecimal(outputsAmount, totalAmount, scale),
Locked: false,
}
if err := State(ctx).Insert(senderChangeOutput); err != nil {
Expand All @@ -288,7 +301,9 @@ func (u *UTXOStore) Mint(ctx router.Context, op *BalanceOperation) error {

// Lock tokens
func (u *UTXOStore) Lock(ctx router.Context, op *BalanceOperation) (*LockId, error) {
// return setLock(ctx, op, true)
if err := router.ValidateRequest(op); err != nil {
return nil, err
}

outputs, err := u.ListOutputs(ctx, &BalanceId{
Symbol: op.Symbol,
Expand Down Expand Up @@ -334,16 +349,121 @@ func (u *UTXOStore) Lock(ctx router.Context, op *BalanceOperation) (*LockId, err
Group: strings.Join(op.Group, `,`),
Address: op.Address,
TxId: ctx.Stub().GetTxID() + ".1",
Amount: decimal.BigIntSubAsDecimal(outputsAmount, opAmount),
Amount: decimal.BigIntSubAsDecimal(outputsAmount, opAmount, op.Amount.Scale),
Locked: false,
}
if err := State(ctx).Insert(senderChangeOutput); err != nil {
return nil, err
}
}

return &LockId{lockedOutput.Symbol, lockedOutput.Group, lockedOutput.Address, lockedOutput.TxId}, nil
}

func (u *UTXOStore) LockBatch(ctx router.Context, ops []*BalanceOperation) ([]*LockId, error) {
var (
opAddress, symbol string
scale int32
group []string
totalAmount = big.NewInt(0)
)

for _, op := range ops {
if err := router.ValidateRequest(op); err != nil {
return nil, err
}

if opAddress == `` {
opAddress = op.Address
}
if op.Address != opAddress {
return nil, ErrOpAddressNotEqual
}

if symbol == `` {
symbol = op.Symbol
}
if op.Symbol != symbol {
return nil, ErrSymbolNotEqual
}

if len(op.Group) > 0 {
panic(`implement me`)
}

scale = op.Amount.Scale

opAmount, err := op.Amount.BigInt()
if err != nil {
return nil, err
}
totalAmount.Add(totalAmount, opAmount)
}

outputs, err := u.ListOutputs(ctx, &BalanceId{
Symbol: symbol,
Group: group,
Address: opAddress,
})
if err != nil {
return nil, err
}

useOutputs, outputsAmount, err := selectOutputsForAmount(outputs, totalAmount, false)
if err != nil {
return nil, err
}

for _, output := range useOutputs {
if err := State(ctx).Delete(output.ID()); err != nil {
return nil, err
}
}

lockIds := make([]*LockId, len(ops))

for id, op := range ops {
txID := ctx.Stub().GetTxID() + fmt.Sprintf(".%v", id)

lockedOutput := &UTXO{
Symbol: op.Symbol,
Group: strings.Join(op.Group, `,`),
Address: op.Address,
TxId: txID,
Amount: op.Amount,
Locked: true,
//Meta: transfer.Meta,
}

lockIds[id] = &LockId{
Symbol: op.Symbol,
Group: strings.Join(op.Group, `,`),
Address: op.Address,
TxId: txID,
}

if err := State(ctx).Insert(lockedOutput); err != nil {
return nil, err
}
}

if outputsAmount.Cmp(totalAmount) == 1 {
senderChangeOutput := &UTXO{
Symbol: symbol,
Group: strings.Join(group, `,`),
Address: opAddress,
TxId: ctx.Stub().GetTxID() + fmt.Sprintf(".%v", len(ops)),
Amount: decimal.BigIntSubAsDecimal(outputsAmount, totalAmount, scale),
Locked: false,
}
if err := State(ctx).Insert(senderChangeOutput); err != nil {
return nil, err
}
}

return lockIds, nil
}

func (u *UTXOStore) LockAll(ctx router.Context, op *BalanceOperation) error {
utxos, err := State(ctx).ListWith(&UTXO{}, state.Key{op.Symbol, strings.Join(op.Group, `,`)}) // todo: ???
if err != nil {
Expand Down Expand Up @@ -379,7 +499,7 @@ func (u *UTXOStore) Burn(ctx router.Context, op *BalanceOperation) error {
return burn(ctx, op, false)
}

// Burn locked tokens
// BurnLock locked tokens
func (u *UTXOStore) BurnLock(ctx router.Context, id *LockId) error {
utxo, err := State(ctx).Get(&UTXOId{Symbol: id.Symbol, Group: id.Group, Address: id.Address, TxId: id.TxId}, &UTXO{})
if err != nil {
Expand All @@ -393,7 +513,7 @@ func (u *UTXOStore) BurnLock(ctx router.Context, id *LockId) error {
return nil
}

// Transfer locked tokens between accounts
// TransferLock locked tokens between accounts
func (u *UTXOStore) TransferLock(ctx router.Context, id *LockId, transfer *TransferOperation) error {
utxo, err := State(ctx).Get(&UTXOId{Symbol: id.Symbol, Group: id.Group, Address: id.Address, TxId: id.TxId}, &UTXO{})
if err != nil {
Expand Down Expand Up @@ -500,7 +620,7 @@ func burn(ctx router.Context, burn *BalanceOperation, locked bool) error {
Group: strings.Join(burn.Group, `,`),
Address: burn.Address,
TxId: ctx.Stub().GetTxID(),
Amount: decimal.BigIntSubAsDecimal(outputsAmount, burnAmount),
Amount: decimal.BigIntSubAsDecimal(outputsAmount, burnAmount, burn.Amount.Scale),
Locked: locked,
}
if err := State(ctx).Insert(senderChangeOutput); err != nil {
Expand Down
Loading

0 comments on commit 65a82cf

Please sign in to comment.