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

refactor(dot/rpc/modules) Add author unit tests, migrate old tests to integration tests #1666

Merged
merged 3 commits into from
Jul 6, 2021
Merged
Show file tree
Hide file tree
Changes from all 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
27 changes: 14 additions & 13 deletions dot/rpc/modules/author.go
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ func NewAuthorModule(logger log.Logger, coreAPI CoreAPI, runtimeAPI RuntimeAPI,
}

// InsertKey inserts a key into the keystore
func (cm *AuthorModule) InsertKey(r *http.Request, req *KeyInsertRequest, res *KeyInsertResponse) error {
func (am *AuthorModule) InsertKey(r *http.Request, req *KeyInsertRequest, res *KeyInsertResponse) error {
keyReq := *req

pkDec, err := common.HexToBytes(keyReq[1])
Expand All @@ -119,22 +119,22 @@ func (cm *AuthorModule) InsertKey(r *http.Request, req *KeyInsertRequest, res *K
return fmt.Errorf("generated public key does not equal provide public key")
}

cm.coreAPI.InsertKey(keyPair)
cm.logger.Info("inserted key into keystore", "key", keyPair.Public().Hex())
am.coreAPI.InsertKey(keyPair)
am.logger.Info("inserted key into keystore", "key", keyPair.Public().Hex())
return nil
}

// HasKey Checks if the keystore has private keys for the given public key and key type.
func (cm *AuthorModule) HasKey(r *http.Request, req *[]string, res *bool) error {
func (am *AuthorModule) HasKey(r *http.Request, req *[]string, res *bool) error {
reqKey := *req
var err error
*res, err = cm.coreAPI.HasKey(reqKey[0], reqKey[1])
*res, err = am.coreAPI.HasKey(reqKey[0], reqKey[1])
return err
}

// PendingExtrinsics Returns all pending extrinsics
func (cm *AuthorModule) PendingExtrinsics(r *http.Request, req *EmptyRequest, res *PendingExtrinsicsResponse) error {
pending := cm.txStateAPI.Pending()
func (am *AuthorModule) PendingExtrinsics(r *http.Request, req *EmptyRequest, res *PendingExtrinsicsResponse) error {
pending := am.txStateAPI.Pending()
resp := make([]string, len(pending))
for idx, tx := range pending {
resp[idx] = common.BytesToHex(tx.Extrinsic)
Expand All @@ -145,29 +145,30 @@ func (cm *AuthorModule) PendingExtrinsics(r *http.Request, req *EmptyRequest, re
}

// RemoveExtrinsic Remove given extrinsic from the pool and temporarily ban it to prevent reimporting
func (cm *AuthorModule) RemoveExtrinsic(r *http.Request, req *ExtrinsicOrHashRequest, res *RemoveExtrinsicsResponse) error {
func (am *AuthorModule) RemoveExtrinsic(r *http.Request, req *ExtrinsicOrHashRequest, res *RemoveExtrinsicsResponse) error {
return nil
}

// RotateKeys Generate new session keys and returns the corresponding public keys
func (cm *AuthorModule) RotateKeys(r *http.Request, req *EmptyRequest, res *KeyRotateResponse) error {
func (am *AuthorModule) RotateKeys(r *http.Request, req *EmptyRequest, res *KeyRotateResponse) error {
return nil
}

// SubmitAndWatchExtrinsic Submit and subscribe to watch an extrinsic until unsubscribed
func (cm *AuthorModule) SubmitAndWatchExtrinsic(r *http.Request, req *Extrinsic, res *ExtrinsicStatus) error {
func (am *AuthorModule) SubmitAndWatchExtrinsic(r *http.Request, req *Extrinsic, res *ExtrinsicStatus) error {
return nil
}

// SubmitExtrinsic Submit a fully formatted extrinsic for block inclusion
func (cm *AuthorModule) SubmitExtrinsic(r *http.Request, req *Extrinsic, res *ExtrinsicHashResponse) error {
func (am *AuthorModule) SubmitExtrinsic(r *http.Request, req *Extrinsic, res *ExtrinsicHashResponse) error {
extBytes, err := common.HexToBytes(req.Data)
if err != nil {
return err
}

ext := types.Extrinsic(extBytes)
err = cm.coreAPI.HandleSubmittedExtrinsic(ext)
am.logger.Crit("[rpc]", "extrinsic", ext)

*res = ExtrinsicHashResponse(ext.Hash().String())
err = am.coreAPI.HandleSubmittedExtrinsic(ext)
return err
}
268 changes: 268 additions & 0 deletions dot/rpc/modules/author_integration_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,268 @@
// +build integration

package modules

import (
"fmt"
"os"
"reflect"
"testing"

"github.com/ChainSafe/gossamer/dot/network"
"github.com/ChainSafe/gossamer/dot/state"
"github.com/ChainSafe/gossamer/dot/types"
"github.com/ChainSafe/gossamer/lib/common"
"github.com/ChainSafe/gossamer/lib/keystore"
"github.com/ChainSafe/gossamer/lib/runtime"
"github.com/ChainSafe/gossamer/lib/runtime/wasmer"
"github.com/ChainSafe/gossamer/lib/transaction"
log "github.com/ChainSafe/log15"
"github.com/stretchr/testify/require"
)

// https://github.com/paritytech/substrate/blob/5420de3face1349a97eb954ae71c5b0b940c31de/core/transaction-pool/src/tests.rs#L95
var testExt = common.MustHexToBytes("0x410284ffd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d01f8efbe48487e57a22abf7e3acd491b7f3528a33a111b1298601554863d27eb129eaa4e718e1365414ff3d028b62bebc651194c6b5001e5c2839b982757e08a8c0000000600ff8eaf04151687736326c9fea17e25fc5287613693c912909cb226aa4794f26a480b00c465f14670")

// invalid transaction (above tx, with last byte changed)
//nolint
var testInvalidExt = []byte{1, 212, 53, 147, 199, 21, 253, 211, 28, 97, 20, 26, 189, 4, 169, 159, 214, 130, 44, 133, 88, 133, 76, 205, 227, 154, 86, 132, 231, 165, 109, 162, 125, 142, 175, 4, 21, 22, 135, 115, 99, 38, 201, 254, 161, 126, 37, 252, 82, 135, 97, 54, 147, 201, 18, 144, 156, 178, 38, 170, 71, 148, 242, 106, 72, 69, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 216, 5, 113, 87, 87, 40, 221, 120, 247, 252, 137, 201, 74, 231, 222, 101, 85, 108, 102, 39, 31, 190, 210, 14, 215, 124, 19, 160, 180, 203, 54, 110, 167, 163, 149, 45, 12, 108, 80, 221, 65, 238, 57, 237, 199, 16, 10, 33, 185, 8, 244, 184, 243, 139, 5, 87, 252, 245, 24, 225, 37, 154, 163, 143}
Comment on lines +23 to +28
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

in general we should try to get rid of these hard coded extrinsics and such and use the centrifuge library to generate them

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I want to move these tests as integration tests for core.Service. I'll keep this in mind for the next PR.


func TestMain(m *testing.M) {
wasmFilePaths, err := runtime.GenerateRuntimeWasmFile()
if err != nil {
log.Error("failed to generate runtime wasm file", err)
os.Exit(1)
}

// Start all tests
code := m.Run()

runtime.RemoveFiles(wasmFilePaths)
os.Exit(code)
}

func TestAuthorModule_Pending(t *testing.T) {
txQueue := state.NewTransactionState()
auth := NewAuthorModule(nil, nil, nil, txQueue)

res := new(PendingExtrinsicsResponse)
err := auth.PendingExtrinsics(nil, nil, res)
if err != nil {
t.Fatal(err)
}

if !reflect.DeepEqual(*res, PendingExtrinsicsResponse([]string{})) {
t.Errorf("Fail: expected: %+v got: %+v\n", *res, PendingExtrinsicsResponse([]string{}))
}

vtx := &transaction.ValidTransaction{
Extrinsic: types.NewExtrinsic(testExt),
Validity: new(transaction.Validity),
}

_, err = txQueue.Push(vtx)
require.NoError(t, err)

err = auth.PendingExtrinsics(nil, nil, res)
if err != nil {
t.Fatal(err)
}

expected := common.BytesToHex(vtx.Extrinsic)
if !reflect.DeepEqual(*res, PendingExtrinsicsResponse([]string{expected})) {
t.Errorf("Fail: expected: %+v got: %+v\n", res, PendingExtrinsicsResponse([]string{expected}))
}
}

func TestAuthorModule_SubmitExtrinsic_Integration(t *testing.T) {
t.Skip()
// setup auth module
txQueue := state.NewTransactionState()

auth := setupAuthModule(t, txQueue)

// create and submit extrinsic
ext := Extrinsic{fmt.Sprintf("0x%x", testExt)}

res := new(ExtrinsicHashResponse)

err := auth.SubmitExtrinsic(nil, &ext, res)
require.Nil(t, err)

// setup expected results
val := &transaction.Validity{
Priority: 69,
Requires: [][]byte{},
Provides: [][]byte{{146, 157, 61, 99, 63, 98, 30, 242, 128, 49, 150, 90, 140, 165, 187, 249}},
Longevity: 64,
Propagate: true,
}
expected := &transaction.ValidTransaction{
Extrinsic: types.NewExtrinsic(testExt),
Validity: val,
}
expectedHash := ExtrinsicHashResponse("0xb20777f4db60ea55b1aeedde2d7b7aff3efeda736b7e2a840b5713348f766078")

inQueue := txQueue.Pop()

// compare results
require.Equal(t, expected, inQueue)
require.Equal(t, expectedHash, *res)
}

func TestAuthorModule_SubmitExtrinsic_invalid(t *testing.T) {
t.Skip()
// setup service
// setup auth module
txQueue := state.NewTransactionState()
auth := setupAuthModule(t, txQueue)

// create and submit extrinsic
ext := Extrinsic{fmt.Sprintf("0x%x", testInvalidExt)}

res := new(ExtrinsicHashResponse)

err := auth.SubmitExtrinsic(nil, &ext, res)
require.EqualError(t, err, runtime.ErrInvalidTransaction.Message)
}

func TestAuthorModule_SubmitExtrinsic_invalid_input(t *testing.T) {
// setup service
// setup auth module
txQueue := state.NewTransactionState()
auth := setupAuthModule(t, txQueue)

// create and submit extrinsic
ext := Extrinsic{fmt.Sprintf("%x", "1")}

res := new(ExtrinsicHashResponse)
err := auth.SubmitExtrinsic(nil, &ext, res)
require.EqualError(t, err, "could not byteify non 0x prefixed string")
}

func TestAuthorModule_SubmitExtrinsic_InQueue(t *testing.T) {
t.Skip()
// setup auth module
txQueue := state.NewTransactionState()

auth := setupAuthModule(t, txQueue)

// create and submit extrinsic
ext := Extrinsic{fmt.Sprintf("0x%x", testExt)}

res := new(ExtrinsicHashResponse)

// setup expected results
val := &transaction.Validity{
Priority: 69,
Requires: [][]byte{},
Provides: [][]byte{{146, 157, 61, 99, 63, 98, 30, 242, 128, 49, 150, 90, 140, 165, 187, 249}},
Longevity: 64,
Propagate: true,
}
expected := &transaction.ValidTransaction{
Extrinsic: types.NewExtrinsic(testExt),
Validity: val,
}

_, err := txQueue.Push(expected)
require.Nil(t, err)

// this should cause error since transaction is already in txQueue
err = auth.SubmitExtrinsic(nil, &ext, res)
require.EqualError(t, err, transaction.ErrTransactionExists.Error())

}

func TestAuthorModule_InsertKey_Valid(t *testing.T) {
auth := setupAuthModule(t, nil)
req := &KeyInsertRequest{"babe", "0xb7e9185065667390d2ad952a5324e8c365c9bf503dcf97c67a5ce861afe97309", "0x6246ddf254e0b4b4e7dffefc8adf69d212b98ac2b579c362b473fec8c40b4c0a"}
res := &KeyInsertResponse{}
err := auth.InsertKey(nil, req, res)
require.Nil(t, err)
require.Len(t, *res, 0) // zero len result on success
}

func TestAuthorModule_InsertKey_Valid_gran_keytype(t *testing.T) {
auth := setupAuthModule(t, nil)
req := &KeyInsertRequest{"gran", "0xb7e9185065667390d2ad952a5324e8c365c9bf503dcf97c67a5ce861afe97309b7e9185065667390d2ad952a5324e8c365c9bf503dcf97c67a5ce861afe97309", "0xb7e9185065667390d2ad952a5324e8c365c9bf503dcf97c67a5ce861afe97309"}
res := &KeyInsertResponse{}
err := auth.InsertKey(nil, req, res)
require.Nil(t, err)

require.Len(t, *res, 0) // zero len result on success
}

func TestAuthorModule_InsertKey_InValid(t *testing.T) {
auth := setupAuthModule(t, nil)
req := &KeyInsertRequest{"babe", "0xb7e9185065667390d2ad952a5324e8c365c9bf503dcf97c67a5ce861afe97309", "0x0000000000000000000000000000000000000000000000000000000000000000"}
res := &KeyInsertResponse{}
err := auth.InsertKey(nil, req, res)
require.EqualError(t, err, "generated public key does not equal provide public key")
}

func TestAuthorModule_InsertKey_UnknownKeyType(t *testing.T) {
auth := setupAuthModule(t, nil)
req := &KeyInsertRequest{"mack", "0xb7e9185065667390d2ad952a5324e8c365c9bf503dcf97c67a5ce861afe97309", "0x6246ddf254e0b4b4e7dffefc8adf69d212b98ac2b579c362b473fec8c40b4c0a"}
res := &KeyInsertResponse{}
err := auth.InsertKey(nil, req, res)
require.EqualError(t, err, "cannot decode key: invalid key type")

}

func TestAuthorModule_HasKey_Integration(t *testing.T) {
auth := setupAuthModule(t, nil)
kr, err := keystore.NewSr25519Keyring()
require.Nil(t, err)

var res bool
req := []string{kr.Alice().Public().Hex(), "babe"}
err = auth.HasKey(nil, &req, &res)
require.NoError(t, err)
require.True(t, res)
}

func TestAuthorModule_HasKey_NotFound(t *testing.T) {
auth := setupAuthModule(t, nil)
kr, err := keystore.NewSr25519Keyring()
require.Nil(t, err)

var res bool
req := []string{kr.Bob().Public().Hex(), "babe"}
err = auth.HasKey(nil, &req, &res)
require.NoError(t, err)
require.False(t, res)
}

func TestAuthorModule_HasKey_InvalidKey(t *testing.T) {
auth := setupAuthModule(t, nil)

var res bool
req := []string{"0xaa11", "babe"}
err := auth.HasKey(nil, &req, &res)
require.EqualError(t, err, "cannot create public key: input is not 32 bytes")
require.False(t, res)
}

func TestAuthorModule_HasKey_InvalidKeyType(t *testing.T) {
auth := setupAuthModule(t, nil)
kr, err := keystore.NewSr25519Keyring()
require.Nil(t, err)

var res bool
req := []string{kr.Alice().Public().Hex(), "xxxx"}
err = auth.HasKey(nil, &req, &res)
require.EqualError(t, err, "unknown key type: xxxx")
require.False(t, res)
}

func setupAuthModule(t *testing.T, txq *state.TransactionState) *AuthorModule {
fmt.Println("calling setupAuthModule")
cs := newCoreService(t, nil)
fmt.Println("called newCoreService")
rt := wasmer.NewTestInstance(t, runtime.NODE_RUNTIME)
t.Cleanup(func() {
rt.Stop()
})
return NewAuthorModule(nil, cs, rt, txq)
}
Loading