This repository has been archived by the owner on Nov 2, 2018. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 441
Add support for offline transaction signing #2907
Open
lukechampine
wants to merge
29
commits into
master
Choose a base branch
from
offline-signing
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from 6 commits
Commits
Show all changes
29 commits
Select commit
Hold shift + click to select a range
d39e94f
add offline signing functionality
lukechampine 1c7efd4
sync before reporting wallet height
lukechampine 4fa416a
add api routes for unspent+sign
lukechampine e959025
add api docs for unspent+sign
lukechampine 6332d01
change sign semantics
lukechampine b3741e7
add wallet sign command
lukechampine 41c5410
generate keys incrementally
lukechampine 32059e7
use new SpendableOutput type for /unspent
lukechampine 277d93a
sign SiafundInputs as well
lukechampine 873500b
Add siatest and client integration for offline signing
ChrisSchinnerl 043674b
Merge pull request #2913 from NebulousLabs/offline-signing-siatest
lukechampine a2bcb24
Merge branch 'master' into offline-signing
90566ab
decode directly into toSign map
lukechampine d408cc1
add docstrings
lukechampine 4050676
document tosign types
lukechampine 64ff690
account for unconfirmed txns in SpendableOutputs
lukechampine 78c2a13
add wallet sign -raw flag, JSON by default
lukechampine d2c89fc
try /wallet/sign before doing keygen
lukechampine c5098c8
include UnlockConditions in SpendableOutput
lukechampine c1c14d7
Revert "include UnlockConditions in SpendableOutput"
lukechampine 0514348
Merge branch 'master' into offline-signing
lukechampine 6b22c87
don't include unconfirmed outputs that may be spent
lukechampine 477a497
add UnlockConditions to SpendableOutput
lukechampine c36c14e
Merge branch 'master' into offline-signing
lukechampine 30a5854
Merge branch 'master' into offline-signing
lukechampine 83967e1
fix TransactionPoolRawPost signature
lukechampine 4fccafd
add wallet broadcast cmd
lukechampine c97a9d7
more helpful signature decoding error
lukechampine f174e41
overhaul SignTransaction
lukechampine File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -719,6 +719,8 @@ func SignTransaction(txn *types.Transaction, seed modules.Seed, toSign map[types | |
return signTransaction(txn, keys, toSign) | ||
} | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I know that it is not required for unexported functions but I like to have comments everywhere :P |
||
// signTransaction signs the specified inputs of txn using the specified keys. | ||
// It returns an error if any of the specified inputs cannot be signed. | ||
func signTransaction(txn *types.Transaction, keys map[types.UnlockHash]spendableKey, toSign map[types.OutputID]types.UnlockHash) error { | ||
signed := 0 | ||
for i, sci := range txn.SiacoinInputs { | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -451,6 +451,8 @@ func TestParallelBuilders(t *testing.T) { | |
} | ||
} | ||
|
||
// TestSignTransaction constructs a valid, signed transaction using the | ||
// wallet's SpendableOutputs and SignTransaction methods. | ||
func TestSignTransaction(t *testing.T) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. missing comment |
||
if testing.Short() { | ||
t.SkipNow() | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
package client | ||
|
||
import ( | ||
"encoding/base64" | ||
"net/url" | ||
|
||
"github.com/NebulousLabs/Sia/encoding" | ||
"github.com/NebulousLabs/Sia/types" | ||
) | ||
|
||
// TransactionpoolRawPost uses the /tpool/raw endpoint to broadcast a | ||
// transaction by adding it to the transactionpool. | ||
func (c *Client) TransactionpoolRawPost(parents []types.Transaction, txn types.Transaction) (err error) { | ||
parentsBytes := encoding.Marshal(parents) | ||
txnBytes := encoding.Marshal(txn) | ||
values := url.Values{} | ||
values.Set("parents", base64.StdEncoding.EncodeToString(parentsBytes)) | ||
values.Set("transaction", base64.StdEncoding.EncodeToString(txnBytes)) | ||
err = c.post("/tpool/raw", values.Encode(), nil) | ||
return | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
package wallet |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
package wallet | ||
|
||
import ( | ||
"testing" | ||
|
||
"github.com/NebulousLabs/Sia/node" | ||
"github.com/NebulousLabs/Sia/siatest" | ||
"github.com/NebulousLabs/Sia/types" | ||
) | ||
|
||
// TestSignTransaction is a integration test for signing transaction offline | ||
// using the API. | ||
func TestSignTransaction(t *testing.T) { | ||
if testing.Short() { | ||
t.SkipNow() | ||
} | ||
testdir, err := siatest.TestDir(t.Name()) | ||
if err != nil { | ||
t.Fatal(err) | ||
} | ||
|
||
// Create a new server | ||
testNode, err := siatest.NewNode(node.AllModules(testdir)) | ||
if err != nil { | ||
t.Fatal(err) | ||
} | ||
defer func() { | ||
if err := testNode.Close(); err != nil { | ||
t.Fatal(err) | ||
} | ||
}() | ||
|
||
// get an output to spend | ||
unspentResp, err := testNode.WalletUnspentGet() | ||
if err != nil { | ||
t.Fatal("failed to get spendable outputs") | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. would be good to report |
||
} | ||
outputs := unspentResp.Outputs | ||
|
||
// create a transaction that sends an output to the void | ||
txn := types.Transaction{ | ||
SiacoinInputs: []types.SiacoinInput{{ | ||
ParentID: types.SiacoinOutputID(outputs[0].ID), | ||
}}, | ||
SiacoinOutputs: []types.SiacoinOutput{{ | ||
Value: outputs[0].Value, | ||
UnlockHash: types.UnlockHash{}, | ||
}}, | ||
} | ||
|
||
// sign the transaction | ||
signResp, err := testNode.WalletSignPost(txn, map[types.OutputID]types.UnlockHash{ | ||
outputs[0].ID: outputs[0].UnlockHash, | ||
}) | ||
if err != nil { | ||
t.Fatal("failed to sign the transaction", err) | ||
} | ||
txn = signResp.Transaction | ||
|
||
// txn should now have unlock condictions and a signature | ||
if txn.SiacoinInputs[0].UnlockConditions.SignaturesRequired == 0 { | ||
t.Fatal("unlock conditions are still unset") | ||
} | ||
if len(txn.TransactionSignatures) == 0 { | ||
t.Fatal("transaction was not signed") | ||
} | ||
|
||
// the resulting transaction should be valid; submit it to the tpool and | ||
// mine a block to confirm it | ||
if err := testNode.TransactionpoolRawPost(nil, txn); err != nil { | ||
t.Fatal("failed to add transaction to pool", err) | ||
} | ||
if err := testNode.MineBlock(); err != nil { | ||
t.Fatal("failed to mine block", err) | ||
} | ||
|
||
// the wallet should no longer list the resulting output as spendable | ||
unspentResp, err = testNode.WalletUnspentGet() | ||
if err != nil { | ||
t.Fatal("failed to get spendable outputs") | ||
} | ||
outputs = unspentResp.Outputs | ||
if len(outputs) != 1 { | ||
t.Fatal("expected one output") | ||
} | ||
if outputs[0].ID == types.OutputID(txn.SiacoinInputs[0].ParentID) { | ||
t.Fatal("spent output still listed as spendable") | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should probably mention that those are
SiacoinOutputID: UnlockHash/Address
pairs.