diff --git a/crypto/sr25519/sr25519.go b/crypto/sr25519/sr25519.go new file mode 100644 index 00000000..f4feae22 --- /dev/null +++ b/crypto/sr25519/sr25519.go @@ -0,0 +1,68 @@ +// Copyright 2020 ChainSafe Systems +// SPDX-License-Identifier: LGPL-3.0-only + +package sr25519 + +import ( + "bytes" + "crypto/rand" + + "github.com/centrifuge/go-substrate-rpc-client/v4/scale" + "github.com/centrifuge/go-substrate-rpc-client/v4/signature" + + "github.com/ethereum/go-ethereum/common/hexutil" +) + +type Keypair struct { + keyringPair *signature.KeyringPair +} + +func GenerateKeypair(network uint16) (*Keypair, error) { + data := make([]byte, 32) + _, err := rand.Read(data) + if err != nil { + return nil, err + } + return NewKeypairFromSeed("//"+hexutil.Encode(data), network) +} + +func NewKeypairFromSeed(seed string, network uint16) (*Keypair, error) { + kp, err := signature.KeyringPairFromSecret(seed, network) + return &Keypair{&kp}, err +} + +func NewKeypairFromKRP(pair signature.KeyringPair) *Keypair { + return &Keypair{&pair} +} + +// AsKeyringPair returns the underlying KeyringPair +func (kp *Keypair) AsKeyringPair() *signature.KeyringPair { + return kp.keyringPair +} + +// Encode uses scale to encode underlying KeyringPair +func (kp *Keypair) Encode() ([]byte, error) { + var buffer = bytes.Buffer{} + err := scale.NewEncoder(&buffer).Encode(kp.keyringPair) + if err != nil { + return buffer.Bytes(), err + } + return buffer.Bytes(), nil +} + +// Decode initializes keypair by decoding input as a KeyringPair +func (kp *Keypair) Decode(in []byte) error { + kp.keyringPair = &signature.KeyringPair{} + + return scale.NewDecoder(bytes.NewReader(in)).Decode(kp.keyringPair) +} + +// Address returns the ss58 formated address +func (kp *Keypair) Address() string { + return kp.keyringPair.Address +} + +// PublicKey returns the publickey encoded as a string +func (kp *Keypair) PublicKey() string { + return hexutil.Encode(kp.keyringPair.PublicKey) +} diff --git a/crypto/sr25519/sr25519_test.go b/crypto/sr25519/sr25519_test.go new file mode 100644 index 00000000..2a14a166 --- /dev/null +++ b/crypto/sr25519/sr25519_test.go @@ -0,0 +1,60 @@ +// Copyright 2020 ChainSafe Systems +// SPDX-License-Identifier: LGPL-3.0-only + +package sr25519 + +import ( + "reflect" + "testing" + + "github.com/centrifuge/go-substrate-rpc-client/v4/signature" +) + +func TestNewKeypairFromSeed(t *testing.T) { + kp, err := NewKeypairFromSeed("//Alice", 42) + if err != nil { + t.Fatal(err) + } + + if kp.PublicKey() == "" || kp.Address() == "" { + t.Fatalf("key is missing data: %#v", kp) + } +} + +func TestKeypair_AsKeyringPair(t *testing.T) { + + kp, err := NewKeypairFromSeed("//Alice", 42) + if err != nil { + t.Fatal(err) + } + + krp := kp.AsKeyringPair() + + // TODO: Add expected output from subkey + + if !reflect.DeepEqual(&signature.TestKeyringPairAlice, krp) { + t.Fatalf("unexpected result.\n\tGot: %#v\n\texpected: %#v\n", krp, &signature.TestKeyringPairAlice) + } + +} + +func TestEncodeAndDecodeKeypair(t *testing.T) { + kp, err := NewKeypairFromSeed("//Alice", 42) + if err != nil { + t.Fatal(err) + } + + enc, err := kp.Encode() + if err != nil { + t.Fatal(err) + } + res := new(Keypair) + err = res.Decode(enc) + if err != nil { + t.Fatal(err) + } + + if !reflect.DeepEqual(res, kp) { + t.Fatalf("Fail: got %#v expected %#v", res, kp) + } +} diff --git a/relayer/message/message.go b/relayer/message/message.go index 32600837..4d0ffd9f 100644 --- a/relayer/message/message.go +++ b/relayer/message/message.go @@ -7,3 +7,12 @@ type Message struct { Data interface{} // Data associated with the message Type MessageType // Message type } + +func NewMessage(source, destination uint8, data interface{}, msgType MessageType) *Message { + return &Message{ + Source: source, + Destination: destination, + Data: data, + Type: msgType, + } +} diff --git a/relayer/proposal/proposal.go b/relayer/proposal/proposal.go index f4f6eebc..456d5ea8 100644 --- a/relayer/proposal/proposal.go +++ b/relayer/proposal/proposal.go @@ -7,3 +7,12 @@ type Proposal struct { Data interface{} Type ProposalType } + +func NewProposal(source uint8, destination uint8, data interface{}, propType ProposalType) *Proposal { + return &Proposal{ + Source: source, + Destination: destination, + Data: data, + Type: propType, + } +}