prepare for hardfork

parent 427f7e71
......@@ -178,7 +178,7 @@ func utilssighashcmd(indexStr, txnStr string) {
}
}
fmt.Println(txn.SigHash(index))
fmt.Println(txn.SigHash(index, 180e3))
}
func utilschecksigcmd(base64Sig, hexHash, pkStr string) {
......
......@@ -578,7 +578,7 @@ func walletsigncmdoffline(txn *types.Transaction, toSign []crypto.Hash) {
case <-done:
}
}()
err = wallet.SignTransaction(txn, seed, toSign)
err = wallet.SignTransaction(txn, seed, toSign, 180e3)
if err != nil {
die("Failed to sign transaction:", err)
}
......
......@@ -58,7 +58,7 @@ func verifyKeysSiag_1_0(uc types.UnlockConditions, folder string, keyname string
PublicKeyIndex: i,
CoveredFields: types.CoveredFields{WholeTransaction: true},
})
sigHash := txn.SigHash(int(j))
sigHash := txn.SigHash(int(j), 0)
sig := crypto.SignHash(sigHash, loadedKeys[i].SecretKey)
txn.TransactionSignatures[j].Signature = sig[:]
i++
......
......@@ -511,7 +511,7 @@ func (cst *consensusSetTester) testFileContractRevision() {
FileContractRevisions: []types.FileContractRevision{fcr},
TransactionSignatures: []types.TransactionSignature{ts},
}
encodedSig := crypto.SignHash(txn.SigHash(0), sk)
encodedSig := crypto.SignHash(txn.SigHash(0, 0), sk)
txn.TransactionSignatures[0].Signature = encodedSig[:]
err = cst.tpool.AcceptTransactionSet([]types.Transaction{txn})
if err != nil {
......
......@@ -150,7 +150,7 @@ func createRevisionSignature(fcr types.FileContractRevision, renterSig types.Tra
FileContractRevisions: []types.FileContractRevision{fcr},
TransactionSignatures: []types.TransactionSignature{renterSig, hostSig},
}
sigHash := txn.SigHash(1)
sigHash := txn.SigHash(1, blockHeight)
encodedSig := crypto.SignHash(sigHash, secretKey)
txn.TransactionSignatures[1].Signature = encodedSig[:]
err := modules.VerifyFileContractRevisionTransactionSignatures(fcr, txn.TransactionSignatures, blockHeight)
......
......@@ -136,7 +136,7 @@ func (c *Contractor) Downloader(pk types.SiaPublicKey, cancel <-chan struct{}) (
}
// create downloader
d, err := c.staticContracts.NewDownloader(host, contract.ID, c.hdb, cancel)
d, err := c.staticContracts.NewDownloader(host, contract.ID, height, c.hdb, cancel)
if err != nil {
return nil, err
}
......
......@@ -257,7 +257,7 @@ func TestReviseContract(t *testing.T) {
}
// sign the transaction
encodedSig := crypto.SignHash(signedTxn.SigHash(0), sk)
encodedSig := crypto.SignHash(signedTxn.SigHash(0, ct.cs.Height()), sk)
signedTxn.TransactionSignatures[0].Signature = encodedSig[:]
err = signedTxn.StandaloneValid(ct.contractor.blockHeight)
......
......@@ -24,6 +24,8 @@ type Downloader struct {
hdb hostDB
host modules.HostDBEntry
once sync.Once
height types.BlockHeight
}
// Sector retrieves the sector with the specified Merkle root, and revises
......@@ -97,7 +99,7 @@ func (hd *Downloader) Sector(root crypto.Hash) (_ modules.RenterContract, _ []by
// send the revision to the host for approval
extendDeadline(hd.conn, connTimeout)
signedTxn, err := negotiateRevision(hd.conn, rev, contract.SecretKey)
signedTxn, err := negotiateRevision(hd.conn, rev, contract.SecretKey, hd.height)
if err == modules.ErrStopResponse {
// if host gracefully closed, close our connection as well; this will
// cause the next download to fail. However, we must delay closing
......@@ -156,7 +158,7 @@ func (hd *Downloader) Close() error {
// NewDownloader initiates the download request loop with a host, and returns a
// Downloader.
func (cs *ContractSet) NewDownloader(host modules.HostDBEntry, id types.FileContractID, hdb hostDB, cancel <-chan struct{}) (_ *Downloader, err error) {
func (cs *ContractSet) NewDownloader(host modules.HostDBEntry, id types.FileContractID, currentHeight types.BlockHeight, hdb hostDB, cancel <-chan struct{}) (_ *Downloader, err error) {
sc, ok := cs.Acquire(id)
if !ok {
return nil, errors.New("invalid contract")
......@@ -200,5 +202,7 @@ func (cs *ContractSet) NewDownloader(host modules.HostDBEntry, id types.FileCont
closeChan: closeChan,
deps: cs.deps,
hdb: hdb,
height: currentHeight,
}, nil
}
......@@ -145,7 +145,7 @@ func (he *Editor) Upload(data []byte) (_ modules.RenterContract, _ crypto.Hash,
// send revision to host and exchange signatures
extendDeadline(he.conn, connTimeout)
signedTxn, err := negotiateRevision(he.conn, rev, contract.SecretKey)
signedTxn, err := negotiateRevision(he.conn, rev, contract.SecretKey, he.height)
if err == modules.ErrStopResponse {
// if host gracefully closed, close our connection as well; this will
// cause the next operation to fail
......@@ -204,12 +204,13 @@ func (cs *ContractSet) NewEditor(host modules.HostDBEntry, id types.FileContract
return &Editor{
host: host,
hdb: hdb,
height: currentHeight,
contractID: id,
contractSet: cs,
conn: conn,
closeChan: closeChan,
deps: cs.deps,
height: currentHeight,
}, nil
}
......
......@@ -215,7 +215,7 @@ func (cs *ContractSet) FormContract(params ContractParams, txnBuilder transactio
FileContractRevisions: []types.FileContractRevision{initRevision},
TransactionSignatures: []types.TransactionSignature{renterRevisionSig},
}
encodedSig := crypto.SignHash(revisionTxn.SigHash(0), ourSK)
encodedSig := crypto.SignHash(revisionTxn.SigHash(0, startHeight), ourSK)
revisionTxn.TransactionSignatures[0].Signature = encodedSig[:]
// Send acceptance and signatures.
......
......@@ -123,7 +123,7 @@ func verifyRecentRevision(conn net.Conn, contract *SafeContract, hostVersion str
// negotiateRevision sends a revision and actions to the host for approval,
// completing one iteration of the revision loop.
func negotiateRevision(conn net.Conn, rev types.FileContractRevision, secretKey crypto.SecretKey) (types.Transaction, error) {
func negotiateRevision(conn net.Conn, rev types.FileContractRevision, secretKey crypto.SecretKey, height types.BlockHeight) (types.Transaction, error) {
// create transaction containing the revision
signedTxn := types.Transaction{
FileContractRevisions: []types.FileContractRevision{rev},
......@@ -134,7 +134,7 @@ func negotiateRevision(conn net.Conn, rev types.FileContractRevision, secretKey
}},
}
// sign the transaction
encodedSig := crypto.SignHash(signedTxn.SigHash(0), secretKey)
encodedSig := crypto.SignHash(signedTxn.SigHash(0, height), secretKey)
signedTxn.TransactionSignatures[0].Signature = encodedSig[:]
// send the revision
......
......@@ -36,7 +36,7 @@ func TestNegotiateRevisionStopResponse(t *testing.T) {
// since the host wrote StopResponse, we should proceed to validating the
// transaction. This will return a known error because we are supplying an
// empty revision.
_, err := negotiateRevision(rConn, types.FileContractRevision{}, crypto.SecretKey{})
_, err := negotiateRevision(rConn, types.FileContractRevision{}, crypto.SecretKey{}, 0)
if err != types.ErrFileContractWindowStartViolation {
t.Fatalf("expected %q, got \"%v\"", types.ErrFileContractWindowStartViolation, err)
}
......@@ -56,7 +56,7 @@ func TestNegotiateRevisionStopResponse(t *testing.T) {
encoding.WriteObject(hConn, types.TransactionSignature{})
}()
expectedErr := "host did not accept transaction signature: sentinel"
_, err = negotiateRevision(rConn, types.FileContractRevision{}, crypto.SecretKey{})
_, err = negotiateRevision(rConn, types.FileContractRevision{}, crypto.SecretKey{}, 0)
if err == nil || err.Error() != expectedErr {
t.Fatalf("expected %q, got \"%v\"", expectedErr, err)
}
......
......@@ -228,7 +228,7 @@ func (cs *ContractSet) Renew(oldContract *SafeContract, params ContractParams, t
FileContractRevisions: []types.FileContractRevision{initRevision},
TransactionSignatures: []types.TransactionSignature{renterRevisionSig},
}
encodedSig := crypto.SignHash(revisionTxn.SigHash(0), ourSK)
encodedSig := crypto.SignHash(revisionTxn.SigHash(0, startHeight), ourSK)
revisionTxn.TransactionSignatures[0].Signature = encodedSig[:]
// Send acceptance and signatures
......
......@@ -84,7 +84,7 @@ func (w *Wallet) managedCreateDefragTransaction() ([]types.Transaction, error) {
// Sign all of the inputs to the parent transaction.
for _, sci := range parentTxn.SiacoinInputs {
addSignatures(&parentTxn, types.FullCoveredFields, sci.UnlockConditions, crypto.Hash(sci.ParentID), w.keys[sci.UnlockConditions.UnlockHash()])
addSignatures(&parentTxn, types.FullCoveredFields, sci.UnlockConditions, crypto.Hash(sci.ParentID), w.keys[sci.UnlockConditions.UnlockHash()], consensusHeight)
}
// Create the defrag transaction.
......@@ -108,7 +108,7 @@ func (w *Wallet) managedCreateDefragTransaction() ([]types.Transaction, error) {
}},
MinerFees: []types.Currency{fee},
}
addSignatures(&txn, types.FullCoveredFields, parentUnlockConditions, crypto.Hash(parentTxn.SiacoinOutputID(0)), w.keys[parentUnlockConditions.UnlockHash()])
addSignatures(&txn, types.FullCoveredFields, parentUnlockConditions, crypto.Hash(parentTxn.SiacoinOutputID(0)), w.keys[parentUnlockConditions.UnlockHash()], consensusHeight)
// Mark all outputs that were spent as spent.
for _, scoid := range spentScoids {
......
......@@ -155,11 +155,17 @@ func (w *Wallet) SignTransaction(txn *types.Transaction, toSign []crypto.Hash) e
return err
}
defer w.tg.Done()
w.mu.RLock()
defer w.mu.RUnlock()
w.mu.Lock()
defer w.mu.Unlock()
if !w.unlocked {
return modules.ErrLockedWallet
}
consensusHeight, err := dbGetConsensusHeight(w.dbTx)
if err != nil {
return err
}
// if toSign is empty, sign all inputs that we have keys for
if len(toSign) == 0 {
for _, sci := range txn.SiacoinInputs {
......@@ -173,7 +179,7 @@ func (w *Wallet) SignTransaction(txn *types.Transaction, toSign []crypto.Hash) e
}
}
}
return signTransaction(txn, w.keys, toSign)
return signTransaction(txn, w.keys, toSign, consensusHeight)
}
// SignTransaction signs txn using secret keys derived from seed. The
......@@ -183,7 +189,7 @@ func (w *Wallet) SignTransaction(txn *types.Transaction, toSign []crypto.Hash) e
// SignTransaction must derive all of the keys from scratch, so it is
// appreciably slower than calling the Wallet.SignTransaction method. Only the
// first 1 million keys are derived.
func SignTransaction(txn *types.Transaction, seed modules.Seed, toSign []crypto.Hash) error {
func SignTransaction(txn *types.Transaction, seed modules.Seed, toSign []crypto.Hash, height types.BlockHeight) error {
if len(toSign) == 0 {
// unlike the wallet method, we can't simply "sign all inputs we have
// keys for," because without generating all of the keys up front, we
......@@ -199,16 +205,16 @@ func SignTransaction(txn *types.Transaction, seed modules.Seed, toSign []crypto.
keys[sk.UnlockConditions.UnlockHash()] = sk
}
keyIndex += keysPerBatch
if err := signTransaction(txn, keys, toSign); err == nil {
if err := signTransaction(txn, keys, toSign, height); err == nil {
return nil
}
}
return signTransaction(txn, keys, toSign)
return signTransaction(txn, keys, toSign, height)
}
// 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 []crypto.Hash) error {
func signTransaction(txn *types.Transaction, keys map[types.UnlockHash]spendableKey, toSign []crypto.Hash, height types.BlockHeight) error {
// helper function to lookup unlock conditions in the txn associated with
// a transaction signature's ParentID
findUnlockConditions := func(id crypto.Hash) (types.UnlockConditions, bool) {
......@@ -271,7 +277,7 @@ func signTransaction(txn *types.Transaction, keys map[types.UnlockHash]spendable
// out. Although we could save a bit of work by not signing it, in
// practice it's probably best to overwrite any existing signatures,
// since we know that ours will be valid.
sigHash := txn.SigHash(sigIndex)
sigHash := txn.SigHash(sigIndex, height)
encodedSig := crypto.SignHash(sigHash, sk)
txn.TransactionSignatures[sigIndex].Signature = encodedSig[:]
}
......
......@@ -160,7 +160,7 @@ func TestSignTransactionNoWallet(t *testing.T) {
}
// can't sign without toSign argument
if err := SignTransaction(&txn, seed, nil); err == nil {
if err := SignTransaction(&txn, seed, nil, 0); err == nil {
t.Fatal("expected error when attempting to sign without specifying ParentIDs")
}
......@@ -169,7 +169,7 @@ func TestSignTransactionNoWallet(t *testing.T) {
txn.TransactionSignatures[0].ParentID,
txn.TransactionSignatures[1].ParentID,
}
if err := SignTransaction(&txn, seed, toSign); err != nil {
if err := SignTransaction(&txn, seed, toSign, 0); err != nil {
t.Fatal(err)
}
// txn should now have a signature
......@@ -368,7 +368,7 @@ func TestWatchOnly(t *testing.T) {
}
// sign the transaction
sig := crypto.SignHash(txn.SigHash(0), sk.SecretKeys[0])
sig := crypto.SignHash(txn.SigHash(0, wt.cs.Height()), sk.SecretKeys[0])
txn.TransactionSignatures[0].Signature = sig[:]
// the resulting transaction should be valid; submit it to the tpool and
......
......@@ -358,9 +358,13 @@ func (w *Wallet) SweepSeed(seed modules.Seed) (coins, funds types.Currency, err
// get an address to spend into
w.mu.Lock()
uc, err := w.nextPrimarySeedAddress(w.dbTx)
height, err2 := dbGetConsensusHeight(w.dbTx)
w.mu.Unlock()
if err != nil {
return
return types.Currency{}, types.Currency{}, err
}
if err2 != nil {
return types.Currency{}, types.Currency{}, err2
}
// scan blockchain for outputs, filtering out 'dust' (outputs that cost
......@@ -496,11 +500,11 @@ func (w *Wallet) SweepSeed(seed modules.Seed) (coins, funds types.Currency, err
txn, parents := tb.View()
for _, output := range txnSiacoinOutputs {
sk := generateSpendableKey(seed, output.seedIndex)
addSignatures(&txn, types.FullCoveredFields, sk.UnlockConditions, crypto.Hash(output.id), sk)
addSignatures(&txn, types.FullCoveredFields, sk.UnlockConditions, crypto.Hash(output.id), sk, height)
}
for _, sfo := range txnSiafundOutputs {
sk := generateSpendableKey(seed, sfo.seedIndex)
addSignatures(&txn, types.FullCoveredFields, sk.UnlockConditions, crypto.Hash(sfo.id), sk)
addSignatures(&txn, types.FullCoveredFields, sk.UnlockConditions, crypto.Hash(sfo.id), sk, height)
}
// Usually, all the inputs will come from swept outputs. However, there is
// an edge case in which inputs will be added from the wallet. To cover
......@@ -509,7 +513,7 @@ func (w *Wallet) SweepSeed(seed modules.Seed) (coins, funds types.Currency, err
w.mu.RLock()
for _, input := range txn.SiacoinInputs {
if key, ok := w.keys[input.UnlockConditions.UnlockHash()]; ok {
addSignatures(&txn, types.FullCoveredFields, input.UnlockConditions, crypto.Hash(input.ParentID), key)
addSignatures(&txn, types.FullCoveredFields, input.UnlockConditions, crypto.Hash(input.ParentID), key, height)
}
}
w.mu.RUnlock()
......
......@@ -50,7 +50,7 @@ type transactionBuilder struct {
// addSignatures will sign a transaction using a spendable key, with support
// for multisig spendable keys. Because of the restricted input, the function
// is compatible with both siacoin inputs and siafund inputs.
func addSignatures(txn *types.Transaction, cf types.CoveredFields, uc types.UnlockConditions, parentID crypto.Hash, spendKey spendableKey) (newSigIndices []int) {
func addSignatures(txn *types.Transaction, cf types.CoveredFields, uc types.UnlockConditions, parentID crypto.Hash, spendKey spendableKey, height types.BlockHeight) (newSigIndices []int) {
// Try to find the matching secret key for each public key - some public
// keys may not have a match. Some secret keys may be used multiple times,
// which is why public keys are used as the outer loop.
......@@ -72,7 +72,7 @@ func addSignatures(txn *types.Transaction, cf types.CoveredFields, uc types.Unlo
newSigIndices = append(newSigIndices, len(txn.TransactionSignatures))
txn.TransactionSignatures = append(txn.TransactionSignatures, sig)
sigIndex := len(txn.TransactionSignatures) - 1
sigHash := txn.SigHash(sigIndex)
sigHash := txn.SigHash(sigIndex, height)
encodedSig := crypto.SignHash(sigHash, spendKey.SecretKeys[j])
txn.TransactionSignatures[sigIndex].Signature = encodedSig[:]
......@@ -225,7 +225,7 @@ func (tb *transactionBuilder) FundSiacoins(amount types.Currency) error {
// Sign all of the inputs to the parent transaction.
for _, sci := range parentTxn.SiacoinInputs {
addSignatures(&parentTxn, types.FullCoveredFields, sci.UnlockConditions, crypto.Hash(sci.ParentID), tb.wallet.keys[sci.UnlockConditions.UnlockHash()])
addSignatures(&parentTxn, types.FullCoveredFields, sci.UnlockConditions, crypto.Hash(sci.ParentID), tb.wallet.keys[sci.UnlockConditions.UnlockHash()], consensusHeight)
}
// Mark the parent output as spent. Must be done after the transaction is
// finished because otherwise the txid and output id will change.
......@@ -357,7 +357,7 @@ func (tb *transactionBuilder) FundSiafunds(amount types.Currency) error {
// Sign all of the inputs to the parent transaction.
for _, sfi := range parentTxn.SiafundInputs {
addSignatures(&parentTxn, types.FullCoveredFields, sfi.UnlockConditions, crypto.Hash(sfi.ParentID), tb.wallet.keys[sfi.UnlockConditions.UnlockHash()])
addSignatures(&parentTxn, types.FullCoveredFields, sfi.UnlockConditions, crypto.Hash(sfi.ParentID), tb.wallet.keys[sfi.UnlockConditions.UnlockHash()], consensusHeight)
}
// Add the exact output.
......@@ -546,6 +546,13 @@ func (tb *transactionBuilder) Sign(wholeTransaction bool) ([]types.Transaction,
return nil, errBuilderAlreadySigned
}
tb.wallet.mu.Lock()
consensusHeight, err := dbGetConsensusHeight(tb.wallet.dbTx)
tb.wallet.mu.Unlock()
if err != nil {
return nil, err
}
// Create the coveredfields struct.
var coveredFields types.CoveredFields
if wholeTransaction {
......@@ -595,7 +602,7 @@ func (tb *transactionBuilder) Sign(wholeTransaction bool) ([]types.Transaction,
if !ok {
return nil, errors.New("transaction builder added an input that it cannot sign")
}
newSigIndices := addSignatures(&tb.transaction, coveredFields, input.UnlockConditions, crypto.Hash(input.ParentID), key)
newSigIndices := addSignatures(&tb.transaction, coveredFields, input.UnlockConditions, crypto.Hash(input.ParentID), key, consensusHeight)
tb.transactionSignatures = append(tb.transactionSignatures, newSigIndices...)
tb.signed = true // Signed is set to true after one successful signature to indicate that future signings can cause issues.
}
......@@ -605,7 +612,7 @@ func (tb *transactionBuilder) Sign(wholeTransaction bool) ([]types.Transaction,
if !ok {
return nil, errors.New("transaction builder added an input that it cannot sign")
}
newSigIndices := addSignatures(&tb.transaction, coveredFields, input.UnlockConditions, crypto.Hash(input.ParentID), key)
newSigIndices := addSignatures(&tb.transaction, coveredFields, input.UnlockConditions, crypto.Hash(input.ParentID), key, consensusHeight)
tb.transactionSignatures = append(tb.transactionSignatures, newSigIndices...)
tb.signed = true // Signed is set to true after one successful signature to indicate that future signings can cause issues.
}
......
......@@ -306,7 +306,11 @@ func TestWatchOnly(t *testing.T) {
}
// sign the transaction
sig := crypto.SignHash(txn.SigHash(0), sk)
cg, err := testNode.ConsensusGet()
if err != nil {
t.Fatal(err)
}
sig := crypto.SignHash(txn.SigHash(0, cg.Height), sk)
txn.TransactionSignatures[0].Signature = sig[:]
// the resulting transaction should be valid; submit it to the tpool and
......
......@@ -180,7 +180,7 @@ func (uc UnlockConditions) UnlockHash() UnlockHash {
// SigHash returns the hash of the fields in a transaction covered by a given
// signature. See CoveredFields for more details.
func (t Transaction) SigHash(i int) (hash crypto.Hash) {
func (t Transaction) SigHash(i int, height BlockHeight) (hash crypto.Hash) {
cf := t.TransactionSignatures[i].CoveredFields
h := crypto.NewHash()
if cf.WholeTransaction {
......@@ -398,7 +398,7 @@ func (t *Transaction) validSignatures(currentHeight BlockHeight) error {
var edSig crypto.Signature
copy(edSig[:], sig.Signature)
sigHash := t.SigHash(i)
sigHash := t.SigHash(i, currentHeight)
err = crypto.VerifyHash(sigHash, edPK, edSig)
if err != nil {
return err
......
......@@ -70,8 +70,8 @@ func TestSigHash(t *testing.T) {
},
}
_ = txn.SigHash(0)
_ = txn.SigHash(1)
_ = txn.SigHash(0, 0)
_ = txn.SigHash(1, 0)
}
......@@ -238,9 +238,9 @@ func TestTransactionValidSignatures(t *testing.T) {
txn.TransactionSignatures[2].ParentID[0] = 2
txn.TransactionSignatures[4].ParentID[0] = 1
txn.TransactionSignatures[5].ParentID[0] = 2
sigHash0 := txn.SigHash(0)
sigHash1 := txn.SigHash(1)
sigHash2 := txn.SigHash(2)
sigHash0 := txn.SigHash(0, 10)
sigHash1 := txn.SigHash(1, 10)
sigHash2 := txn.SigHash(2, 10)
sig0 := crypto.SignHash(sigHash0, sk)
sig1 := crypto.SignHash(sigHash1, sk)
sig2 := crypto.SignHash(sigHash2, sk)
......
......@@ -38,7 +38,7 @@ func BenchmarkStandaloneValid(b *testing.B) {
}
// Transaction must be constructed before signing
for i := 0; i < numSigs; i++ {
sigHash := txn.SigHash(i)
sigHash := txn.SigHash(i, 0)
sig0 := crypto.SignHash(sigHash, sk[i])
txn.TransactionSignatures[i].Signature = sig0[:]
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment