예제 #1
0
파일: channel.go 프로젝트: conseweb/lnd
// VerifyNewCommitmentSigs...
func (c *ChannelUpdate) VerifyNewCommitmentSigs(ourSig, theirSig []byte) error {
	c.lnChannel.stateMtx.RLock()
	defer c.lnChannel.stateMtx.RUnlock()

	var err error
	var scriptSig []byte
	channelState := c.lnChannel.channelState

	// When initially generating the redeemScript, we sorted the serialized
	// public keys in descending order. So we do a quick comparison in order
	// ensure the signatures appear on the Script Virual Machine stack in
	// the correct order.
	redeemScript := channelState.FundingRedeemScript
	ourKey := channelState.OurCommitKey.PubKey().SerializeCompressed()
	theirKey := channelState.TheirCommitKey.SerializeCompressed()
	scriptSig, err = spendMultiSig(redeemScript, ourKey, ourSig, theirKey, theirSig)
	if err != nil {
		return err
	}

	// Attach the scriptSig to our commitment transaction's only input,
	// then validate that the scriptSig executes correctly.
	commitTx := c.ourPendingCommitTx
	commitTx.TxIn[0].SignatureScript = scriptSig
	vm, err := txscript.NewEngine(c.lnChannel.fundingP2SH, commitTx, 0,
		txscript.StandardVerifyFlags, nil)
	if err != nil {
		return err
	}

	return vm.Execute()
}
예제 #2
0
func main() {
	if len(os.Args) < 2 {
		log.Println("Not enough arguments")
		log.Println("Usage:", os.Args[0], " FILE")
		os.Exit(0)
	}
	log.SetFlags(log.LstdFlags | log.Lshortfile)

	file, err := os.Open(os.Args[1])
	if err != nil {
		log.Fatal(err)
	}
	defer file.Close()

	scanner := bufio.NewScanner(file)
	i := 0
	lines := make([]string, 5)
	for scanner.Scan() {
		lines[i] = scanner.Text()
		i += 1
	}

	if err := scanner.Err(); err != nil {
		log.Fatal(err)
	}

	scriptPubkey, err := hex.DecodeString(lines[0])
	if err != nil {
		log.Fatal(err)
	}

	txToBytes, err := hex.DecodeString(lines[1])
	if err != nil {
		log.Fatal(err)
	}

	txTo, err := btcutil.NewTxFromBytes(txToBytes)
	if err != nil {
		log.Fatal(err)
	}
	txToMsg := txTo.MsgTx()

	nIn, err := strconv.Atoi(lines[2])
	if err != nil {
		log.Fatal(err)
	}

	script, err := txscript.NewEngine(scriptPubkey, txToMsg, int(nIn), 0)
	err = script.Execute()
	if err != nil {
		fmt.Println("0")
		fmt.Println(err.Error())
	} else {
		fmt.Println("1")
	}
}
예제 #3
0
// validateSigScripts executes the signature script of the tx input with the
// given index, returning an error if it fails.
func validateSigScript(msgtx *wire.MsgTx, idx int, pkScript []byte) error {
	vm, err := txscript.NewEngine(pkScript, msgtx, idx,
		txscript.StandardVerifyFlags, nil)
	if err != nil {
		return newError(ErrTxSigning, "cannot create script engine", err)
	}
	if err = vm.Execute(); err != nil {
		return newError(ErrTxSigning, "cannot validate tx signature", err)
	}
	return nil
}
예제 #4
0
func validateMsgTx(msgtx *wire.MsgTx, prevOutputs []wtxmgr.Credit) error {
	for i := range msgtx.TxIn {
		vm, err := txscript.NewEngine(prevOutputs[i].PkScript,
			msgtx, i, txscript.StandardVerifyFlags, nil)
		if err != nil {
			return fmt.Errorf("cannot create script engine: %s", err)
		}
		if err = vm.Execute(); err != nil {
			return fmt.Errorf("cannot validate transaction: %s", err)
		}
	}
	return nil
}
예제 #5
0
// validateMsgTx verifies transaction input scripts for tx.  All previous output
// scripts from outputs redeemed by the transaction, in the same order they are
// spent, must be passed in the prevScripts slice.
func validateMsgTx(tx *wire.MsgTx, prevScripts [][]byte) error {
	for i, prevScript := range prevScripts {
		vm, err := txscript.NewEngine(prevScript, tx, i,
			txscript.StandardVerifyFlags, nil)
		if err != nil {
			return fmt.Errorf("cannot create script engine: %s", err)
		}
		err = vm.Execute()
		if err != nil {
			return fmt.Errorf("cannot validate transaction: %s", err)
		}
	}
	return nil
}
예제 #6
0
// TestInvalidFlagCombinations ensures the script engine returns the expected
// error when disallowed flag combinations are specified.
func TestInvalidFlagCombinations(t *testing.T) {
	t.Parallel()

	tests := []txscript.ScriptFlags{
		txscript.ScriptVerifyCleanStack,
	}

	// tx with almost empty scripts.
	tx := &wire.MsgTx{
		Version: 1,
		TxIn: []*wire.TxIn{
			{
				PreviousOutPoint: wire.OutPoint{
					Hash: wire.ShaHash([32]byte{
						0xc9, 0x97, 0xa5, 0xe5,
						0x6e, 0x10, 0x41, 0x02,
						0xfa, 0x20, 0x9c, 0x6a,
						0x85, 0x2d, 0xd9, 0x06,
						0x60, 0xa2, 0x0b, 0x2d,
						0x9c, 0x35, 0x24, 0x23,
						0xed, 0xce, 0x25, 0x85,
						0x7f, 0xcd, 0x37, 0x04,
					}),
					Index: 0,
				},
				SignatureScript: []uint8{txscript.OP_NOP},
				Sequence:        4294967295,
			},
		},
		TxOut: []*wire.TxOut{
			{
				Value:    1000000000,
				PkScript: nil,
			},
		},
		LockTime: 0,
	}
	pkScript := []byte{txscript.OP_NOP}

	for i, test := range tests {
		_, err := txscript.NewEngine(pkScript, tx, 0, test)
		if err != txscript.ErrInvalidFlags {
			t.Fatalf("TestInvalidFlagCombinations #%d unexpected "+
				"error: %v", i, err)
		}
	}
}
예제 #7
0
파일: sign_test.go 프로젝트: cdecker/btcd
func checkScripts(msg string, tx *wire.MsgTx, idx int, sigScript, pkScript []byte) error {
	tx.TxIn[idx].SignatureScript = sigScript
	vm, err := txscript.NewEngine(pkScript, tx, idx,
		txscript.ScriptBip16|txscript.ScriptVerifyDERSignatures, nil)
	if err != nil {
		return fmt.Errorf("failed to make script engine for %s: %v",
			msg, err)
	}

	err = vm.Execute()
	if err != nil {
		return fmt.Errorf("invalid script signature for %s: %v", msg,
			err)
	}

	return nil
}
예제 #8
0
func testBasicWalletReservationWorkFlow(lnwallet *LightningWallet, t *testing.T) {
	// Create our test wallet, will have a total of 20 BTC available for
	bobNode, err := newBobNode()
	if err != nil {
		t.Fatalf("unable to create bob node: %v", err)
	}

	// Bob initiates a channel funded with 5 BTC for each side, so 10
	// BTC total. He also generates 2 BTC in change.
	fundingAmount := btcutil.Amount(5 * 1e8)
	chanReservation, err := lnwallet.InitChannelReservation(fundingAmount,
		SIGHASH, bobNode.id, 4)
	if err != nil {
		t.Fatalf("unable to initialize funding reservation: %v", err)
	}

	// The channel reservation should now be populated with a multi-sig key
	// from our HD chain, a change output with 3 BTC, and 2 outputs selected
	// of 4 BTC each. Additionally, the rest of the items needed to fufill a
	// funding contribution should also have been filled in.
	ourContribution := chanReservation.OurContribution()
	if len(ourContribution.Inputs) != 2 {
		t.Fatalf("outputs for funding tx not properly selected, have %v "+
			"outputs should have 2", len(ourContribution.Inputs))
	}
	if ourContribution.ChangeOutputs[0].Value != 3e8 {
		t.Fatalf("coin selection failed, change output should be 3e8 "+
			"satoshis, is instead %v", ourContribution.ChangeOutputs[0].Value)
	}
	if ourContribution.MultiSigKey == nil {
		t.Fatalf("alice's key for multi-sig not found")
	}
	if ourContribution.CommitKey == nil {
		t.Fatalf("alice's key for commit not found")
	}
	if ourContribution.DeliveryAddress == nil {
		t.Fatalf("alice's final delivery address not found")
	}
	if bytes.Equal(ourContribution.RevocationHash[:], zeroHash) {
		t.Fatalf("alice's revocation hash not found")
	}
	if ourContribution.CsvDelay == 0 {
		t.Fatalf("csv delay not set")
	}

	// Bob sends over his output, change addr, pub keys, initial revocation,
	// final delivery address, and his accepted csv delay for the commitmen
	// t transactions.
	if err := chanReservation.ProcessContribution(bobNode.Contribution()); err != nil {
		t.Fatalf("unable to add bob's funds to the funding tx: %v", err)
	}

	// At this point, the reservation should have our signatures, and a
	// partial funding transaction (missing bob's sigs).
	theirContribution := chanReservation.TheirContribution()
	ourFundingSigs, ourCommitSig := chanReservation.OurSignatures()
	if len(ourFundingSigs) != 2 {
		t.Fatalf("only %v of our sigs present, should have 2",
			len(ourFundingSigs))
	}
	if ourCommitSig == nil {
		t.Fatalf("commitment sig not found")
	}
	// Additionally, the funding tx should have been populated.
	if chanReservation.partialState.FundingTx == nil {
		t.Fatalf("funding transaction never created!")
	}
	// Their funds should also be filled in.
	if len(theirContribution.Inputs) != 1 {
		t.Fatalf("bob's outputs for funding tx not properly selected, have %v "+
			"outputs should have 2", len(theirContribution.Inputs))
	}
	if theirContribution.ChangeOutputs[0].Value != 2e8 {
		t.Fatalf("bob should have one change output with value 2e8"+
			"satoshis, is instead %v",
			theirContribution.ChangeOutputs[0].Value)
	}
	if theirContribution.MultiSigKey == nil {
		t.Fatalf("bob's key for multi-sig not found")
	}
	if theirContribution.CommitKey == nil {
		t.Fatalf("bob's key for commit tx not found")
	}
	if theirContribution.DeliveryAddress == nil {
		t.Fatalf("bob's final delivery address not found")
	}
	if bytes.Equal(theirContribution.RevocationHash[:], zeroHash) {
		t.Fatalf("bob's revocaiton hash not found")
	}

	// Alice responds with her output, change addr, multi-sig key and signatures.
	// Bob then responds with his signatures.
	bobsSigs, err := bobNode.signFundingTx(chanReservation.partialState.FundingTx)
	if err != nil {
		t.Fatalf("unable to sign inputs for bob: %v", err)
	}
	commitSig, err := bobNode.signCommitTx(
		chanReservation.partialState.OurCommitTx,
		chanReservation.partialState.FundingRedeemScript)
	if err != nil {
		t.Fatalf("bob is unable to sign alice's commit tx: %v", err)
	}
	if err := chanReservation.CompleteReservation(bobsSigs, commitSig); err != nil {
		t.Fatalf("unable to complete funding tx: %v", err)
	}

	// At this point, the channel can be considered "open" when the funding
	// txn hits a "comfortable" depth.

	fundingTx := chanReservation.FinalFundingTx()

	// The resulting active channel state should have been persisted to the DB.
	channel, err := lnwallet.ChannelDB.FetchOpenChannel(bobNode.id)
	if err != nil {
		t.Fatalf("unable to retrieve channel from DB: %v", err)
	}
	if channel.FundingTx.TxSha() != fundingTx.TxSha() {
		t.Fatalf("channel state not properly saved")
	}

	// The funding tx should now be valid and complete.
	// Check each input and ensure all scripts are fully valid.
	// TODO(roasbeef): remove this loop after nodetest hooked up.
	var zeroHash wire.ShaHash
	for i, input := range fundingTx.TxIn {
		var pkscript []byte
		// Bob's txin
		if bytes.Equal(input.PreviousOutPoint.Hash.Bytes(),
			zeroHash.Bytes()) {
			pkscript = bobNode.changeOutputs[0].PkScript
		} else {
			// Does the wallet know about the txin?
			txDetail, err := lnwallet.TxStore.TxDetails(&input.PreviousOutPoint.Hash)
			if txDetail == nil || err != nil {
				t.Fatalf("txstore can't find tx detail, err: %v", err)
			}
			prevIndex := input.PreviousOutPoint.Index
			pkscript = txDetail.TxRecord.MsgTx.TxOut[prevIndex].PkScript
		}

		vm, err := txscript.NewEngine(pkscript,
			fundingTx, i, txscript.StandardVerifyFlags, nil)
		if err != nil {
			// TODO(roasbeef): cancel at this stage if invalid sigs?
			t.Fatalf("cannot create script engine: %s", err)
		}
		if err = vm.Execute(); err != nil {
			t.Fatalf("cannot validate transaction: %s", err)
		}
	}
}
예제 #9
0
파일: scriptval.go 프로젝트: tb00/btcd
// validateHandler consumes items to validate from the internal validate channel
// and returns the result of the validation on the internal result channel. It
// must be run as a goroutine.
func (v *txValidator) validateHandler() {
out:
	for {
		select {
		case txVI := <-v.validateChan:
			// Ensure the referenced input transaction is available.
			txIn := txVI.txIn
			originTxHash := &txIn.PreviousOutPoint.Hash
			originTxIndex := txIn.PreviousOutPoint.Index
			txEntry := v.utxoView.LookupEntry(originTxHash)
			if txEntry == nil {
				str := fmt.Sprintf("unable to find input "+
					"transaction %v referenced from "+
					"transaction %v", originTxHash,
					txVI.tx.Hash())
				err := ruleError(ErrMissingTx, str)
				v.sendResult(err)
				break out
			}

			// Ensure the referenced input transaction public key
			// script is available.
			pkScript := txEntry.PkScriptByIndex(originTxIndex)
			if pkScript == nil {
				str := fmt.Sprintf("unable to find unspent "+
					"output %v script referenced from "+
					"transaction %s:%d",
					txIn.PreviousOutPoint, txVI.tx.Hash(),
					txVI.txInIndex)
				err := ruleError(ErrBadTxInput, str)
				v.sendResult(err)
				break out
			}

			// Create a new script engine for the script pair.
			sigScript := txIn.SignatureScript
			vm, err := txscript.NewEngine(pkScript, txVI.tx.MsgTx(),
				txVI.txInIndex, v.flags, v.sigCache)
			if err != nil {
				str := fmt.Sprintf("failed to parse input "+
					"%s:%d which references output %s:%d - "+
					"%v (input script bytes %x, prev output "+
					"script bytes %x)", txVI.tx.Hash(),
					txVI.txInIndex, originTxHash,
					originTxIndex, err, sigScript, pkScript)
				err := ruleError(ErrScriptMalformed, str)
				v.sendResult(err)
				break out
			}

			// Execute the script pair.
			if err := vm.Execute(); err != nil {
				str := fmt.Sprintf("failed to validate input "+
					"%s:%d which references output %s:%d - "+
					"%v (input script bytes %x, prev output "+
					"script bytes %x)", txVI.tx.Hash(),
					txVI.txInIndex, originTxHash,
					originTxIndex, err, sigScript, pkScript)
				err := ruleError(ErrScriptValidation, str)
				v.sendResult(err)
				break out
			}

			// Validation succeeded.
			v.sendResult(nil)

		case <-v.quitChan:
			break out
		}
	}
}
예제 #10
0
파일: sign_test.go 프로젝트: cdecker/btcd
// Test the sigscript generation for valid and invalid inputs, all
// hashTypes, and with and without compression.  This test creates
// sigscripts to spend fake coinbase inputs, as sigscripts cannot be
// created for the MsgTxs in txTests, since they come from the blockchain
// and we don't have the private keys.
func TestSignatureScript(t *testing.T) {
	t.Parallel()

	privKey, _ := btcec.PrivKeyFromBytes(btcec.S256(), privKeyD)

nexttest:
	for i := range sigScriptTests {
		tx := wire.NewMsgTx()

		output := wire.NewTxOut(500, []byte{txscript.OP_RETURN})
		tx.AddTxOut(output)

		for range sigScriptTests[i].inputs {
			txin := wire.NewTxIn(coinbaseOutPoint, nil)
			tx.AddTxIn(txin)
		}

		var script []byte
		var err error
		for j := range tx.TxIn {
			var idx int
			if sigScriptTests[i].inputs[j].indexOutOfRange {
				t.Errorf("at test %v", sigScriptTests[i].name)
				idx = len(sigScriptTests[i].inputs)
			} else {
				idx = j
			}
			script, err = txscript.SignatureScript(tx, idx,
				sigScriptTests[i].inputs[j].txout.PkScript,
				sigScriptTests[i].hashType, privKey,
				sigScriptTests[i].compress)

			if (err == nil) != sigScriptTests[i].inputs[j].sigscriptGenerates {
				if err == nil {
					t.Errorf("passed test '%v' incorrectly",
						sigScriptTests[i].name)
				} else {
					t.Errorf("failed test '%v': %v",
						sigScriptTests[i].name, err)
				}
				continue nexttest
			}
			if !sigScriptTests[i].inputs[j].sigscriptGenerates {
				// done with this test
				continue nexttest
			}

			tx.TxIn[j].SignatureScript = script
		}

		// If testing using a correct sigscript but for an incorrect
		// index, use last input script for first input.  Requires > 0
		// inputs for test.
		if sigScriptTests[i].scriptAtWrongIndex {
			tx.TxIn[0].SignatureScript = script
			sigScriptTests[i].inputs[0].inputValidates = false
		}

		// Validate tx input scripts
		scriptFlags := txscript.ScriptBip16 | txscript.ScriptVerifyDERSignatures
		for j := range tx.TxIn {
			vm, err := txscript.NewEngine(sigScriptTests[i].
				inputs[j].txout.PkScript, tx, j, scriptFlags, nil)
			if err != nil {
				t.Errorf("cannot create script vm for test %v: %v",
					sigScriptTests[i].name, err)
				continue nexttest
			}
			err = vm.Execute()
			if (err == nil) != sigScriptTests[i].inputs[j].inputValidates {
				if err == nil {
					t.Errorf("passed test '%v' validation incorrectly: %v",
						sigScriptTests[i].name, err)
				} else {
					t.Errorf("failed test '%v' validation: %v",
						sigScriptTests[i].name, err)
				}
				continue nexttest
			}
		}
	}
}
예제 #11
0
// TestCheckErrorCondition tests the execute early test in CheckErrorCondition()
// since most code paths are tested elsewhere.
func TestCheckErrorCondition(t *testing.T) {
	t.Parallel()

	// tx with almost empty scripts.
	tx := &wire.MsgTx{
		Version: 1,
		TxIn: []*wire.TxIn{
			{
				PreviousOutPoint: wire.OutPoint{
					Hash: wire.ShaHash([32]byte{
						0xc9, 0x97, 0xa5, 0xe5,
						0x6e, 0x10, 0x41, 0x02,
						0xfa, 0x20, 0x9c, 0x6a,
						0x85, 0x2d, 0xd9, 0x06,
						0x60, 0xa2, 0x0b, 0x2d,
						0x9c, 0x35, 0x24, 0x23,
						0xed, 0xce, 0x25, 0x85,
						0x7f, 0xcd, 0x37, 0x04,
					}),
					Index: 0,
				},
				SignatureScript: []uint8{},
				Sequence:        4294967295,
			},
		},
		TxOut: []*wire.TxOut{
			{
				Value:    1000000000,
				PkScript: nil,
			},
		},
		LockTime: 0,
	}
	pkScript := []byte{
		txscript.OP_NOP,
		txscript.OP_NOP,
		txscript.OP_NOP,
		txscript.OP_NOP,
		txscript.OP_NOP,
		txscript.OP_NOP,
		txscript.OP_NOP,
		txscript.OP_NOP,
		txscript.OP_NOP,
		txscript.OP_NOP,
		txscript.OP_TRUE,
	}

	vm, err := txscript.NewEngine(pkScript, tx, 0, 0)
	if err != nil {
		t.Errorf("failed to create script: %v", err)
	}

	for i := 0; i < len(pkScript)-1; i++ {
		done, err := vm.Step()
		if err != nil {
			t.Errorf("failed to step %dth time: %v", i, err)
			return
		}
		if done {
			t.Errorf("finshed early on %dth time", i)
			return
		}

		err = vm.CheckErrorCondition(false)
		if err != txscript.ErrStackScriptUnfinished {
			t.Errorf("got unexepected error %v on %dth iteration",
				err, i)
			return
		}
	}
	done, err := vm.Step()
	if err != nil {
		t.Errorf("final step failed %v", err)
		return
	}
	if !done {
		t.Errorf("final step isn't done!")
		return
	}

	err = vm.CheckErrorCondition(false)
	if err != nil {
		t.Errorf("unexpected error %v on final check", err)
	}
}
예제 #12
0
// TestBadPC sets the pc to a deliberately bad result then confirms that Step()
// and Disasm fail correctly.
func TestBadPC(t *testing.T) {
	t.Parallel()

	type pcTest struct {
		script, off int
	}
	pcTests := []pcTest{
		{
			script: 2,
			off:    0,
		},
		{
			script: 0,
			off:    2,
		},
	}
	// tx with almost empty scripts.
	tx := &wire.MsgTx{
		Version: 1,
		TxIn: []*wire.TxIn{
			{
				PreviousOutPoint: wire.OutPoint{
					Hash: wire.ShaHash([32]byte{
						0xc9, 0x97, 0xa5, 0xe5,
						0x6e, 0x10, 0x41, 0x02,
						0xfa, 0x20, 0x9c, 0x6a,
						0x85, 0x2d, 0xd9, 0x06,
						0x60, 0xa2, 0x0b, 0x2d,
						0x9c, 0x35, 0x24, 0x23,
						0xed, 0xce, 0x25, 0x85,
						0x7f, 0xcd, 0x37, 0x04,
					}),
					Index: 0,
				},
				SignatureScript: []uint8{txscript.OP_NOP},
				Sequence:        4294967295,
			},
		},
		TxOut: []*wire.TxOut{
			{
				Value:    1000000000,
				PkScript: nil,
			},
		},
		LockTime: 0,
	}
	pkScript := []byte{txscript.OP_NOP}

	for _, test := range pcTests {
		vm, err := txscript.NewEngine(pkScript, tx, 0, 0)
		if err != nil {
			t.Errorf("Failed to create script: %v", err)
		}

		// set to after all scripts
		vm.TstSetPC(test.script, test.off)

		_, err = vm.Step()
		if err == nil {
			t.Errorf("Step with invalid pc (%v) succeeds!", test)
			continue
		}

		_, err = vm.DisasmPC()
		if err == nil {
			t.Errorf("DisasmPC with invalid pc (%v) succeeds!",
				test)
		}
	}
}
예제 #13
0
파일: wallet.go 프로젝트: mkl-/lnd
// handleFundingCounterPartySigs is the final step in the channel reservation
// workflow. During this setp, we validate *all* the received signatures for
// inputs to the funding transaction. If any of these are invalid, we bail,
// and forcibly cancel this funding request. Additionally, we ensure that the
// signature we received from the counterparty for our version of the commitment
// transaction allows us to spend from the funding output with the addition of
// our signature.
func (l *LightningWallet) handleFundingCounterPartySigs(msg *addCounterPartySigsMsg) {
	l.limboMtx.RLock()
	pendingReservation, ok := l.fundingLimbo[msg.pendingFundingID]
	l.limboMtx.RUnlock()
	if !ok {
		msg.err <- fmt.Errorf("attempted to update non-existant funding state")
		return
	}

	// Grab the mutex on the ChannelReservation to ensure thead-safety
	pendingReservation.Lock()
	defer pendingReservation.Unlock()

	// Now we can complete the funding transaction by adding their
	// signatures to their inputs.
	pendingReservation.theirFundingSigs = msg.theirFundingSigs
	fundingTx := pendingReservation.partialState.FundingTx
	for i, txin := range fundingTx.TxIn {
		if txin.SignatureScript == nil {
			// Fetch the alleged previous output along with the
			// pkscript referenced by this input.
			prevOut := txin.PreviousOutPoint
			output, err := l.rpc.GetTxOut(&prevOut.Hash, prevOut.Index, false)
			if output == nil {
				// TODO(roasbeef): do this at the start to avoid wasting out time?
				//  8 or a set of nodes "we" run with exposed unauthenticated RPC?
				msg.err <- fmt.Errorf("input to funding tx does not exist: %v", err)
				return
			}
			pkscript, err := hex.DecodeString(output.ScriptPubKey.Hex)
			if err != nil {
				msg.err <- err
				return
			}

			// Ensure that the signature is valid.
			vm, err := txscript.NewEngine(pkscript,
				fundingTx, i, txscript.StandardVerifyFlags, nil)
			if err != nil {
				// TODO(roasbeef): cancel at this stage if invalid sigs?
				msg.err <- fmt.Errorf("cannot create script engine: %s", err)
				return
			}
			if err = vm.Execute(); err != nil {
				msg.err <- fmt.Errorf("cannot validate transaction: %s", err)
				return
			}

			txin.SignatureScript = pendingReservation.theirFundingSigs[i]
		}
	}

	// At this point, we can also record and verify their signature for our
	// commitment transaction.
	pendingReservation.theirCommitmentSig = msg.theirCommitmentSig
	commitTx := pendingReservation.partialState.OurCommitTx
	theirKey := pendingReservation.theirContribution.MultiSigKey
	ourKey := pendingReservation.partialState.MultiSigKey

	// Re-generate both the redeemScript and p2sh output. We sign the
	// redeemScript script, but include the p2sh output as the subscript
	// for verification.
	redeemScript := pendingReservation.partialState.FundingRedeemScript
	p2sh, err := scriptHashPkScript(redeemScript)
	if err != nil {
		msg.err <- err
		return
	}

	// First, we sign our copy of the commitment transaction ourselves.
	ourCommitSig, err := txscript.RawTxInSignature(commitTx, 0, redeemScript,
		txscript.SigHashAll, ourKey)
	if err != nil {
		msg.err <- err
		return
	}

	// Next, create the spending scriptSig, and then verify that the script
	// is complete, allowing us to spend from the funding transaction.
	//
	// When initially generating the redeemScript, we sorted the serialized
	// public keys in descending order. So we do a quick comparison in order
	// ensure the signatures appear on the Script Virual Machine stack in
	// the correct order.
	var scriptSig []byte
	theirCommitSig := msg.theirCommitmentSig
	if bytes.Compare(ourKey.PubKey().SerializeCompressed(), theirKey.SerializeCompressed()) == -1 {
		scriptSig, err = spendMultiSig(redeemScript, theirCommitSig, ourCommitSig)
	} else {
		scriptSig, err = spendMultiSig(redeemScript, ourCommitSig, theirCommitSig)
	}
	if err != nil {
		msg.err <- err
		return
	}

	// Finally, create an instance of a Script VM, and ensure that the
	// Script executes succesfully.
	commitTx.TxIn[0].SignatureScript = scriptSig
	vm, err := txscript.NewEngine(p2sh, commitTx, 0,
		txscript.StandardVerifyFlags, nil)
	if err != nil {
		msg.err <- err
		return
	}
	if err := vm.Execute(); err != nil {
		msg.err <- fmt.Errorf("counterparty's commitment signature is invalid: %v", err)
		return
	}

	// Funding complete, this entry can be removed from limbo.
	l.limboMtx.Lock()
	delete(l.fundingLimbo, pendingReservation.reservationID)
	// TODO(roasbeef): unlock outputs here, Store.InsertTx will handle marking
	// input in unconfirmed tx, so future coin selects don't pick it up
	//  * also record location of change address so can use AddCredit
	l.limboMtx.Unlock()

	// Add the complete funding transaction to the DB, in it's open bucket
	// which will be used for the lifetime of this channel.
	err = l.ChannelDB.PutOpenChannel(pendingReservation.partialState)

	// Create a goroutine to watch the chain so we can open the channel once
	// the funding tx has enough confirmations.
	// TODO(roasbeef): add number of confs to the confi
	go l.openChannelAfterConfirmations(pendingReservation, 3)

	msg.err <- err
}
예제 #14
0
// This example demonstrates manually creating and signing a redeem transaction.
func ExampleSignTxOutput() {
	// Ordinarily the private key would come from whatever storage mechanism
	// is being used, but for this example just hard code it.
	privKeyBytes, err := hex.DecodeString("22a47fa09a223f2aa079edf85a7c2" +
		"d4f8720ee63e502ee2869afab7de234b80c")
	if err != nil {
		fmt.Println(err)
		return
	}
	privKey, pubKey := btcec.PrivKeyFromBytes(btcec.S256(), privKeyBytes)
	pubKeyHash := btcutil.Hash160(pubKey.SerializeCompressed())
	addr, err := btcutil.NewAddressPubKeyHash(pubKeyHash,
		&chaincfg.MainNetParams)
	if err != nil {
		fmt.Println(err)
		return
	}

	// For this example, create a fake transaction that represents what
	// would ordinarily be the real transaction that is being spent.  It
	// contains a single output that pays to address in the amount of 1 BTC.
	originTx := wire.NewMsgTx()
	prevOut := wire.NewOutPoint(&wire.ShaHash{}, ^uint32(0))
	txIn := wire.NewTxIn(prevOut, []byte{txscript.OP_0, txscript.OP_0})
	originTx.AddTxIn(txIn)
	pkScript, err := txscript.PayToAddrScript(addr)
	if err != nil {
		fmt.Println(err)
		return
	}
	txOut := wire.NewTxOut(100000000, pkScript)
	originTx.AddTxOut(txOut)
	originTxHash := originTx.TxSha()

	// Create the transaction to redeem the fake transaction.
	redeemTx := wire.NewMsgTx()

	// Add the input(s) the redeeming transaction will spend.  There is no
	// signature script at this point since it hasn't been created or signed
	// yet, hence nil is provided for it.
	prevOut = wire.NewOutPoint(&originTxHash, 0)
	txIn = wire.NewTxIn(prevOut, nil)
	redeemTx.AddTxIn(txIn)

	// Ordinarily this would contain that actual destination of the funds,
	// but for this example don't bother.
	txOut = wire.NewTxOut(0, nil)
	redeemTx.AddTxOut(txOut)

	// Sign the redeeming transaction.
	lookupKey := func(a btcutil.Address) (*btcec.PrivateKey, bool, error) {
		// Ordinarily this function would involve looking up the private
		// key for the provided address, but since the only thing being
		// signed in this example uses the address associated with the
		// private key from above, simply return it with the compressed
		// flag set since the address is using the associated compressed
		// public key.
		//
		// NOTE: If you want to prove the code is actually signing the
		// transaction properly, uncomment the following line which
		// intentionally returns an invalid key to sign with, which in
		// turn will result in a failure during the script execution
		// when verifying the signature.
		//
		// privKey.D.SetInt64(12345)
		//
		return privKey, true, nil
	}
	// Notice that the script database parameter is nil here since it isn't
	// used.  It must be specified when pay-to-script-hash transactions are
	// being signed.
	sigScript, err := txscript.SignTxOutput(&chaincfg.MainNetParams,
		redeemTx, 0, originTx.TxOut[0].PkScript, txscript.SigHashAll,
		txscript.KeyClosure(lookupKey), nil, nil)
	if err != nil {
		fmt.Println(err)
		return
	}
	redeemTx.TxIn[0].SignatureScript = sigScript

	// Prove that the transaction has been validly signed by executing the
	// script pair.
	flags := txscript.ScriptBip16 | txscript.ScriptVerifyDERSignatures |
		txscript.ScriptStrictMultiSig |
		txscript.ScriptDiscourageUpgradableNops
	vm, err := txscript.NewEngine(originTx.TxOut[0].PkScript, redeemTx, 0,
		flags)
	if err != nil {
		fmt.Println(err)
		return
	}
	if err := vm.Execute(); err != nil {
		fmt.Println(err)
		return
	}
	fmt.Println("Transaction successfully signed")

	// Output:
	// Transaction successfully signed
}
예제 #15
0
// validateHandler consumes items to validate from the internal validate channel
// and returns the result of the validation on the internal result channel. It
// must be run as a goroutine.
func (v *txValidator) validateHandler() {
out:
	for {
		select {
		case txVI := <-v.validateChan:
			// Ensure the referenced input transaction is available.
			txIn := txVI.txIn
			originTxHash := &txIn.PreviousOutPoint.Hash
			originTx, exists := v.txStore[*originTxHash]
			if !exists || originTx.Err != nil || originTx.Tx == nil {
				str := fmt.Sprintf("unable to find input "+
					"transaction %v referenced from "+
					"transaction %v", originTxHash,
					txVI.tx.Sha())
				err := ruleError(ErrMissingTx, str)
				v.sendResult(err)
				break out
			}
			originMsgTx := originTx.Tx.MsgTx()

			// Ensure the output index in the referenced transaction
			// is available.
			originTxIndex := txIn.PreviousOutPoint.Index
			if originTxIndex >= uint32(len(originMsgTx.TxOut)) {
				str := fmt.Sprintf("out of bounds "+
					"input index %d in transaction %v "+
					"referenced from transaction %v",
					originTxIndex, originTxHash,
					txVI.tx.Sha())
				err := ruleError(ErrBadTxInput, str)
				v.sendResult(err)
				break out
			}

			// Create a new script engine for the script pair.
			sigScript := txIn.SignatureScript
			pkScript := originMsgTx.TxOut[originTxIndex].PkScript
			vm, err := txscript.NewEngine(pkScript, txVI.tx.MsgTx(),
				txVI.txInIndex, v.flags, v.sigCache)
			if err != nil {
				str := fmt.Sprintf("failed to parse input "+
					"%s:%d which references output %s:%d - "+
					"%v (input script bytes %x, prev output "+
					"script bytes %x)", txVI.tx.Sha(),
					txVI.txInIndex, originTxHash,
					originTxIndex, err, sigScript, pkScript)
				err := ruleError(ErrScriptMalformed, str)
				v.sendResult(err)
				break out
			}

			// Execute the script pair.
			if err := vm.Execute(); err != nil {
				str := fmt.Sprintf("failed to validate input "+
					"%s:%d which references output %s:%d - "+
					"%v (input script bytes %x, prev output "+
					"script bytes %x)", txVI.tx.Sha(),
					txVI.txInIndex, originTxHash,
					originTxIndex, err, sigScript, pkScript)
				err := ruleError(ErrScriptValidation, str)
				v.sendResult(err)
				break out
			}

			// Validation succeeded.
			v.sendResult(nil)

		case <-v.quitChan:
			break out
		}
	}
}