Skip to content

Commit

Permalink
Simply KeystoreAdapter interface (#297)
Browse files Browse the repository at this point in the history
  • Loading branch information
krehermann authored Jun 2, 2023
1 parent 3d81867 commit 62ee8f9
Show file tree
Hide file tree
Showing 2 changed files with 62 additions and 15 deletions.
26 changes: 11 additions & 15 deletions relayer/pkg/chainlink/txm/keystore.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package txm

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

Expand All @@ -13,42 +14,37 @@ import (

// KeystoreAdapter is a starknet-specific adaption layer to translate between the generic Loop Keystore (bytes) and
// the type specific caigo Keystore (big.Int)
// The loop.Keystore must be produce a byte representation that can be parsed by the Decode func implementation
// Users of the interface are responsible to ensure this compatibility.
type KeystoreAdapter interface {
caigo.Keystore
// Loopp must return a LOOPp Keystore implementation whose Sign func
// is compatible with the [Decode] func implementation
Loopp() loop.Keystore
// Decode translates from the raw signature of the LOOPp Keystore to that of the Caigo Keystore
Decode(ctx context.Context, rawSignature []byte) (*big.Int, *big.Int, error)
}

// keystoreAdapter implements [KeystoreAdapter]
// keystoreAdapter implements [KeystoreAdapter].
type keystoreAdapter struct {
looppKs loop.Keystore
}

// NewKeystoreAdapter instantiates the KeystoreAdapter interface
// The implementation requires that the given [looppKs] produces a signature [loop.Keystore.Sign]
// that is []byte representation of [adapters.Signature]
// Callers are responsible for ensuring that the given LOOPp Keystore encodes
// signatures that can be parsed by the Decode function
// signatures correctly.
func NewKeystoreAdapter(lk loop.Keystore) KeystoreAdapter {
return &keystoreAdapter{looppKs: lk}
}

// Sign implements the caigo Keystore Sign func.
var ErrBadAdapterEncoding = errors.New("failed to decode raw signature as adapter signature")

// Sign implements the caigo Keystore Sign func. Returns [ErrBadAdapterSignature] if the signature cannot be
// decoded from the [loop.Keystore] implementation
func (ca *keystoreAdapter) Sign(ctx context.Context, senderAddress string, hash *big.Int) (*big.Int, *big.Int, error) {
raw, err := ca.looppKs.Sign(ctx, senderAddress, hash.Bytes())
if err != nil {
return nil, nil, fmt.Errorf("error computing loopp keystore signature: %w", err)
}
return ca.Decode(ctx, raw)
}

func (ca *keystoreAdapter) Decode(ctx context.Context, rawSignature []byte) (x *big.Int, y *big.Int, err error) {
starknetSig, serr := adapters.SignatureFromBytes(rawSignature)
starknetSig, serr := adapters.SignatureFromBytes(raw)
if serr != nil {
return nil, nil, fmt.Errorf("error creating starknet signature from raw signature: %w", serr)
return nil, nil, fmt.Errorf("%w: %w", ErrBadAdapterEncoding, serr)
}
return starknetSig.Ints()
}
Expand Down
51 changes: 51 additions & 0 deletions relayer/pkg/chainlink/txm/keystore_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package txm_test

import (
"context"
"math/big"
"testing"

"github.com/stretchr/testify/require"

"github.com/smartcontractkit/chainlink-relay/pkg/loop"
adapters "github.com/smartcontractkit/chainlink-relay/pkg/loop/adapters/starknet"
"github.com/smartcontractkit/chainlink-starknet/relayer/pkg/chainlink/txm"
)

func TestKeystoreAdapterImpl(t *testing.T) {
t.Run("valid loop keystore impl", func(t *testing.T) {
goodLoopSignFn := func(ctx context.Context, account string, data []byte) (signed []byte, err error) {
sig, err := adapters.SignatureFromBigInts(big.NewInt(7), big.NewInt(11))
require.NoError(t, err)
return sig.Bytes()
}
ksa := txm.NewKeystoreAdapter(&testLoopKeystore{signFn: goodLoopSignFn})

_, _, err := ksa.Sign(context.Background(), "anything", big.NewInt(42))
require.NoError(t, err)
})
t.Run("invalid loop keystore impl", func(t *testing.T) {
badLoopSignFn := func(ctx context.Context, account string, data []byte) (signed []byte, err error) {
return []byte("not an adapter signature"), nil
}
ksa := txm.NewKeystoreAdapter(&testLoopKeystore{signFn: badLoopSignFn})

_, _, err := ksa.Sign(context.Background(), "anything", big.NewInt(42))
require.ErrorIs(t, err, txm.ErrBadAdapterEncoding)
})

}

type testLoopKeystore struct {
signFn func(ctx context.Context, account string, data []byte) (signed []byte, err error)
}

var _ loop.Keystore = &testLoopKeystore{}

func (lk *testLoopKeystore) Sign(ctx context.Context, account string, data []byte) (signed []byte, err error) {
return lk.signFn(ctx, account, data)
}

func (lk *testLoopKeystore) Accounts(ctx context.Context) (accounts []string, err error) {
return nil, nil
}

0 comments on commit 62ee8f9

Please sign in to comment.