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

[Constructor] Inject Public Keys During Transaction Construction #133

Merged
merged 4 commits into from
Sep 4, 2020
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
25 changes: 23 additions & 2 deletions constructor/coordinator/coordinator.go
Original file line number Diff line number Diff line change
Expand Up @@ -190,9 +190,10 @@ func (c *Coordinator) findJob(
// createTransaction constructs and signs a transaction with the provided intent.
func (c *Coordinator) createTransaction(
ctx context.Context,
dbTx storage.DatabaseTransaction,
broadcast *job.Broadcast,
) (*types.TransactionIdentifier, string, error) {
metadataRequest, err := c.helper.Preprocess(
metadataRequest, requiredPublicKeys, err := c.helper.Preprocess(
ctx,
broadcast.Network,
broadcast.Intent,
Expand All @@ -202,10 +203,25 @@ func (c *Coordinator) createTransaction(
return nil, "", fmt.Errorf("%w: unable to preprocess", err)
}

publicKeys := make([]*types.PublicKey, len(requiredPublicKeys))
for i, accountIdentifier := range requiredPublicKeys {
keyPair, err := c.helper.GetKey(ctx, dbTx, accountIdentifier.Address)
if err != nil {
return nil, "", fmt.Errorf(
"%w: unable to find key for address %s",
err,
accountIdentifier.Address,
)
}

publicKeys[i] = keyPair.PublicKey
}

requiredMetadata, err := c.helper.Metadata(
ctx,
broadcast.Network,
metadataRequest,
publicKeys,
)
if err != nil {
return nil, "", fmt.Errorf("%w: unable to construct metadata", err)
Expand All @@ -216,6 +232,7 @@ func (c *Coordinator) createTransaction(
broadcast.Network,
broadcast.Intent,
requiredMetadata,
publicKeys,
)
if err != nil {
return nil, "", fmt.Errorf("%w: unable to construct payloads", err)
Expand Down Expand Up @@ -483,7 +500,11 @@ func (c *Coordinator) Process(
var transactionCreated *types.TransactionIdentifier
if broadcast != nil {
// Construct Transaction
transactionIdentifier, networkTransaction, err := c.createTransaction(ctx, broadcast)
transactionIdentifier, networkTransaction, err := c.createTransaction(
ctx,
dbTx,
broadcast,
)
if err != nil {
return fmt.Errorf("%w: unable to create transaction", err)
}
Expand Down
63 changes: 61 additions & 2 deletions constructor/coordinator/coordinator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import (

"github.com/coinbase/rosetta-sdk-go/asserter"
"github.com/coinbase/rosetta-sdk-go/constructor/job"
"github.com/coinbase/rosetta-sdk-go/keys"
mocks "github.com/coinbase/rosetta-sdk-go/mocks/constructor/coordinator"
"github.com/coinbase/rosetta-sdk-go/parser"
"github.com/coinbase/rosetta-sdk-go/storage"
Expand Down Expand Up @@ -546,7 +547,7 @@ func TestProcess(t *testing.T) {
map[string]interface{}{
"test": "works",
},
).Return(metadataOptions, nil).Once()
).Return(metadataOptions, nil, nil).Once()
fetchedMetadata := map[string]interface{}{
"tx_meta": "help",
}
Expand All @@ -555,6 +556,7 @@ func TestProcess(t *testing.T) {
ctx,
network,
metadataOptions,
[]*types.PublicKey{},
).Return(fetchedMetadata, nil).Once()

unsignedTx := "unsigned transaction"
Expand All @@ -571,6 +573,7 @@ func TestProcess(t *testing.T) {
network,
ops,
fetchedMetadata,
[]*types.PublicKey{},
).Return(unsignedTx, signingPayloads, nil).Once()
helper.On(
"Parse",
Expand Down Expand Up @@ -950,7 +953,43 @@ func TestProcess_Failed(t *testing.T) {
map[string]interface{}{
"test": "works",
},
).Return(metadataOptions, nil).Once()
).Return(metadataOptions, []*types.AccountIdentifier{
{
Address: "hello",
},
{
Address: "hello2",
},
}, nil).Once()
helper.On(
"GetKey",
ctx,
dbTx,
"hello",
).Return(
&keys.KeyPair{
PublicKey: &types.PublicKey{
Bytes: []byte("hello"),
CurveType: types.Secp256k1,
},
},
nil,
).Once()
helper.On(
"GetKey",
ctx,
dbTx,
"hello2",
).Return(
&keys.KeyPair{
PublicKey: &types.PublicKey{
Bytes: []byte("hello2"),
CurveType: types.Edwards25519,
},
},
nil,
).Once()

fetchedMetadata := map[string]interface{}{
"tx_meta": "help",
}
Expand All @@ -959,6 +998,16 @@ func TestProcess_Failed(t *testing.T) {
ctx,
network,
metadataOptions,
[]*types.PublicKey{
{
Bytes: []byte("hello"),
CurveType: types.Secp256k1,
},
{
Bytes: []byte("hello2"),
CurveType: types.Edwards25519,
},
},
).Return(fetchedMetadata, nil).Once()

unsignedTx := "unsigned transaction"
Expand All @@ -975,6 +1024,16 @@ func TestProcess_Failed(t *testing.T) {
network,
ops,
fetchedMetadata,
[]*types.PublicKey{
{
Bytes: []byte("hello"),
CurveType: types.Secp256k1,
},
{
Bytes: []byte("hello2"),
CurveType: types.Edwards25519,
},
},
).Return(unsignedTx, signingPayloads, nil).Once()
helper.On(
"Parse",
Expand Down
12 changes: 11 additions & 1 deletion constructor/coordinator/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,14 @@ type Helper interface {
*keys.KeyPair,
) error

// GetKey is called to get the *types.KeyPair
// associated with an address.
GetKey(
context.Context,
storage.DatabaseTransaction,
string, // address
) (*keys.KeyPair, error)

// AllAddresses returns a slice of all known addresses.
AllAddresses(
context.Context,
Expand Down Expand Up @@ -119,14 +127,15 @@ type Helper interface {
*types.NetworkIdentifier,
[]*types.Operation,
map[string]interface{},
) (map[string]interface{}, error)
) (map[string]interface{}, []*types.AccountIdentifier, error)

// Metadata calls the /construction/metadata endpoint
// using the online node.
Metadata(
context.Context,
*types.NetworkIdentifier,
map[string]interface{},
[]*types.PublicKey,
) (map[string]interface{}, error)

// Payloads calls the /construction/payloads endpoint
Expand All @@ -136,6 +145,7 @@ type Helper interface {
*types.NetworkIdentifier,
[]*types.Operation,
map[string]interface{},
[]*types.PublicKey,
) (string, []*types.SigningPayload, error)

// Parse calls the /construction/parse endpoint
Expand Down
12 changes: 8 additions & 4 deletions fetcher/construction.go
Original file line number Diff line number Diff line change
Expand Up @@ -132,11 +132,13 @@ func (f *Fetcher) ConstructionMetadata(
ctx context.Context,
network *types.NetworkIdentifier,
options map[string]interface{},
publicKeys []*types.PublicKey,
) (map[string]interface{}, *Error) {
metadata, clientErr, err := f.rosettaClient.ConstructionAPI.ConstructionMetadata(ctx,
&types.ConstructionMetadataRequest{
NetworkIdentifier: network,
Options: options,
PublicKeys: publicKeys,
},
)
if err != nil {
Expand Down Expand Up @@ -209,12 +211,14 @@ func (f *Fetcher) ConstructionPayloads(
network *types.NetworkIdentifier,
operations []*types.Operation,
metadata map[string]interface{},
publicKeys []*types.PublicKey,
) (string, []*types.SigningPayload, *Error) {
response, clientErr, err := f.rosettaClient.ConstructionAPI.ConstructionPayloads(ctx,
&types.ConstructionPayloadsRequest{
NetworkIdentifier: network,
Operations: operations,
Metadata: metadata,
PublicKeys: publicKeys,
},
)

Expand Down Expand Up @@ -248,7 +252,7 @@ func (f *Fetcher) ConstructionPreprocess(
network *types.NetworkIdentifier,
operations []*types.Operation,
metadata map[string]interface{},
) (map[string]interface{}, *Error) {
) (map[string]interface{}, []*types.AccountIdentifier, *Error) {
response, clientErr, err := f.rosettaClient.ConstructionAPI.ConstructionPreprocess(ctx,
&types.ConstructionPreprocessRequest{
NetworkIdentifier: network,
Expand All @@ -262,17 +266,17 @@ func (f *Fetcher) ConstructionPreprocess(
Err: fmt.Errorf("%w: /construction/preprocess %s", ErrRequestFailed, err.Error()),
ClientErr: clientErr,
}
return nil, fetcherErr
return nil, nil, fetcherErr
}

if err := asserter.ConstructionPreprocessResponse(response); err != nil {
fetcherErr := &Error{
Err: fmt.Errorf("%w: /construction/preprocess %s", ErrAssertionFailed, err.Error()),
}
return nil, fetcherErr
return nil, nil, fetcherErr
}

return response.Options, nil
return response.Options, response.RequiredPublicKeys, nil
}

// ConstructionSubmit returns the validated response
Expand Down
Loading