示例#1
0
// This example demonstrates creating a script which pays to a decred address.
// It also prints the created script hex and uses the DisasmString function to
// display the disassembled script.
func ExamplePayToAddrScript() {
	// Parse the address to send the coins to into a dcrutil.Address
	// which is useful to ensure the accuracy of the address and determine
	// the address type.  It is also required for the upcoming call to
	// PayToAddrScript.
	addressStr := "DsSej1qR3Fyc8kV176DCh9n9cY9nqf9Quxk"
	address, err := dcrutil.DecodeAddress(addressStr, &chaincfg.MainNetParams)
	if err != nil {
		fmt.Println(err)
		return
	}

	// Create a public key script that pays to the address.
	script, err := txscript.PayToAddrScript(address)
	if err != nil {
		fmt.Println(err)
		return
	}
	fmt.Printf("Script Hex: %x\n", script)

	disasm, err := txscript.DisasmString(script)
	if err != nil {
		fmt.Println(err)
		return
	}
	fmt.Println("Script Disassembly:", disasm)

	// Output:
	// Script Hex: 76a914128004ff2fcaf13b2b91eb654b1dc2b674f7ec6188ac
	// Script Disassembly: OP_DUP OP_HASH160 128004ff2fcaf13b2b91eb654b1dc2b674f7ec61 OP_EQUALVERIFY OP_CHECKSIG
}
示例#2
0
// TstCreateSeriesCredits creates a new credit for every item in the amounts
// slice, locked to the given series' address with branch==1 and index==0.
func TstCreateSeriesCredits(t *testing.T, pool *Pool, seriesID uint32, amounts []int64) []credit {
	addr := TstNewWithdrawalAddress(t, pool, seriesID, Branch(1), Index(0))
	pkScript, err := txscript.PayToAddrScript(addr.addr)
	if err != nil {
		t.Fatal(err)
	}
	msgTx := createMsgTx(pkScript, amounts)
	txSha := msgTx.TxSha()
	credits := make([]credit, len(amounts))
	for i := range msgTx.TxOut {
		c := wtxmgr.Credit{
			OutPoint: wire.OutPoint{
				Hash:  txSha,
				Index: uint32(i),
			},
			BlockMeta: wtxmgr.BlockMeta{
				Block: wtxmgr.Block{Height: TstInputsBlock},
			},
			Amount:   dcrutil.Amount(msgTx.TxOut[i].Value),
			PkScript: msgTx.TxOut[i].PkScript,
		}
		credits[i] = newCredit(c, *addr)
	}
	return credits
}
示例#3
0
文件: main.go 项目: decred/dcrwallet
// makeDestinationScriptSource creates a ChangeSource which is used to receive
// all correlated previous input value.  A non-change address is created by this
// function.
func makeDestinationScriptSource(rpcClient *dcrrpcclient.Client, accountName string) txauthor.ChangeSource {
	return func() ([]byte, error) {
		destinationAddress, err := rpcClient.GetNewAddress(accountName)
		if err != nil {
			return nil, err
		}
		return txscript.PayToAddrScript(destinationAddress)
	}
}
func TestFakeTxs(t *testing.T) {
	// First we need a wallet.
	w, err := keystore.NewStore("banana wallet", "", []byte("banana"),
		wire.MainNet, &keystore.BlockStamp{}, 100)
	if err != nil {
		t.Errorf("Can not create encrypted wallet: %s", err)
		return
	}
	a := &Wallet{
		Wallet:          w,
		lockedOutpoints: map[wire.OutPoint]struct{}{},
	}

	w.Unlock([]byte("banana"))

	// Create and add a fake Utxo so we have some funds to spend.
	//
	// This will pass validation because txcscript is unaware of invalid
	// tx inputs, however, this example would fail in dcrd.
	utxo := &tx.Utxo{}
	addr, err := w.NextChainedAddress(&keystore.BlockStamp{}, 100)
	if err != nil {
		t.Errorf("Cannot get next address: %s", err)
		return
	}
	copy(utxo.AddrHash[:], addr.ScriptAddress())
	ophash := (chainhash.Hash)([...]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,
		12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27,
		28, 29, 30, 31, 32})
	out := wire.NewOutPoint(&ophash, 0)
	utxo.Out = tx.OutPoint(*out)
	ss, err := txscript.PayToAddrScript(addr)
	if err != nil {
		t.Errorf("Could not create utxo PkScript: %s", err)
		return
	}
	utxo.Subscript = tx.PkScript(ss)
	utxo.Amt = 1000000
	utxo.Height = 12345
	a.UtxoStore = append(a.UtxoStore, utxo)

	// Fake our current block height so dcrd doesn't need to be queried.
	curBlock.BlockStamp.Height = 12346

	// Create the transaction.
	pairs := map[string]int64{
		"17XhEvq9Nahdj7Xe1nv6oRe1tEmaHUuynH": 5000,
	}
	_, err = a.txToPairs(pairs, 1)
	if err != nil {
		t.Errorf("Tx creation failed: %s", err)
		return
	}
}
示例#5
0
func TstCreatePkScript(t *testing.T, p *Pool, seriesID uint32, branch Branch, idx Index) []byte {
	script := TstEnsureUsedAddr(t, p, seriesID, branch, idx)
	addr, err := p.addressFor(script)
	if err != nil {
		t.Fatal(err)
	}
	pkScript, err := txscript.PayToAddrScript(addr)
	if err != nil {
		t.Fatal(err)
	}
	return pkScript
}
func TestSignMultiSigUTXOPkScriptNotP2SH(t *testing.T) {
	tearDown, pool, _ := TstCreatePoolAndTxStore(t)
	defer tearDown()

	mgr := pool.Manager()
	tx := createWithdrawalTx(t, pool, []int64{4e6}, []int64{})
	addr, _ := dcrutil.DecodeAddress("1MirQ9bwyQcGVJPwKUgapu5ouK2E2Ey4gX", mgr.ChainParams())
	pubKeyHashPkScript, _ := txscript.PayToAddrScript(addr.(*dcrutil.AddressPubKeyHash))
	msgtx := tx.toMsgTx()

	err := signMultiSigUTXO(mgr, msgtx, 0, pubKeyHashPkScript, []RawSig{RawSig{}})

	TstCheckError(t, "", err, ErrTxSigning)
}
示例#7
0
// finalizeCurrentTx finalizes the transaction in w.current, moves it to the
// list of finalized transactions and replaces w.current with a new empty
// transaction.
func (w *withdrawal) finalizeCurrentTx() error {
	log.Debug("Finalizing current transaction")
	tx := w.current
	if len(tx.outputs) == 0 {
		log.Debug("Current transaction has no outputs, doing nothing")
		return nil
	}

	pkScript, err := txscript.PayToAddrScript(w.status.nextChangeAddr.addr)
	if err != nil {
		return newError(ErrWithdrawalProcessing, "failed to generate pkScript for change address", err)
	}
	if tx.addChange(pkScript) {
		var err error
		w.status.nextChangeAddr, err = nextChangeAddress(w.status.nextChangeAddr)
		if err != nil {
			return newError(ErrWithdrawalProcessing, "failed to get next change address", err)
		}
	}

	ntxid := tx.ntxid()
	for i, txOut := range tx.outputs {
		outputStatus := w.status.outputs[txOut.request.outBailmentID()]
		outputStatus.addOutpoint(
			OutBailmentOutpoint{ntxid: ntxid, index: uint32(i), amount: txOut.amount})
	}

	// Check that WithdrawalOutput entries with status==success have the sum of
	// their outpoint amounts matching the requested amount.
	for _, txOut := range tx.outputs {
		// Look up the original request we received because txOut.request may
		// represent a split request and thus have a different amount from the
		// original one.
		outputStatus := w.status.outputs[txOut.request.outBailmentID()]
		origRequest := outputStatus.request
		amtFulfilled := dcrutil.Amount(0)
		for _, outpoint := range outputStatus.outpoints {
			amtFulfilled += outpoint.amount
		}
		if outputStatus.status == statusSuccess && amtFulfilled != origRequest.Amount {
			msg := fmt.Sprintf("%s was not completely fulfilled; only %v fulfilled", origRequest,
				amtFulfilled)
			return newError(ErrWithdrawalProcessing, msg, nil)
		}
	}

	w.transactions = append(w.transactions, tx)
	w.current = newWithdrawalTx(w.txOptions)
	return nil
}
示例#8
0
func (s *walletServer) FundTransaction(ctx context.Context, req *pb.FundTransactionRequest) (
	*pb.FundTransactionResponse, error) {

	policy := wallet.OutputSelectionPolicy{
		Account:               req.Account,
		RequiredConfirmations: req.RequiredConfirmations,
	}
	unspentOutputs, err := s.wallet.UnspentOutputs(policy)
	if err != nil {
		return nil, translateError(err)
	}

	selectedOutputs := make([]*pb.FundTransactionResponse_PreviousOutput, 0, len(unspentOutputs))
	var totalAmount dcrutil.Amount
	for _, output := range unspentOutputs {
		selectedOutputs = append(selectedOutputs, &pb.FundTransactionResponse_PreviousOutput{
			TransactionHash: output.OutPoint.Hash[:],
			OutputIndex:     output.OutPoint.Index,
			Amount:          output.Output.Value,
			PkScript:        output.Output.PkScript,
			ReceiveTime:     output.ReceiveTime.Unix(),
			FromCoinbase:    output.OutputKind == wallet.OutputKindCoinbase,
			Tree:            int32(output.OutPoint.Tree),
		})
		totalAmount += dcrutil.Amount(output.Output.Value)

		if req.TargetAmount != 0 && totalAmount > dcrutil.Amount(req.TargetAmount) {
			break
		}
	}

	var changeScript []byte
	if req.IncludeChangeScript && totalAmount > dcrutil.Amount(req.TargetAmount) {
		changeAddr, err := s.wallet.NewAddress(req.Account,
			waddrmgr.InternalBranch)
		if err != nil {
			return nil, translateError(err)
		}
		changeScript, err = txscript.PayToAddrScript(changeAddr)
		if err != nil {
			return nil, translateError(err)
		}
	}

	return &pb.FundTransactionResponse{
		SelectedOutputs: selectedOutputs,
		TotalAmount:     int64(totalAmount),
		ChangePkScript:  changeScript,
	}, nil
}
示例#9
0
func TstNewOutputRequest(t *testing.T, transaction uint32, address string, amount dcrutil.Amount,
	net *chaincfg.Params) OutputRequest {
	addr, err := dcrutil.DecodeAddress(address, net)
	if err != nil {
		t.Fatalf("Unable to decode address %s", address)
	}
	pkScript, err := txscript.PayToAddrScript(addr)
	if err != nil {
		t.Fatalf("Unable to generate pkScript for %v", addr)
	}
	return OutputRequest{
		PkScript:    pkScript,
		Address:     addr,
		Amount:      amount,
		Server:      "server",
		Transaction: transaction,
	}
}
示例#10
0
func TestSignMultiSigUTXORedeemScriptNotFound(t *testing.T) {
	tearDown, pool, _ := TstCreatePoolAndTxStore(t)
	defer tearDown()

	mgr := pool.Manager()
	tx := createWithdrawalTx(t, pool, []int64{4e6}, []int64{})
	// This is a P2SH address for which the addr manager doesn't have the redeem
	// script.
	addr, _ := dcrutil.DecodeAddress("3Hb4xcebcKg4DiETJfwjh8sF4uDw9rqtVC", mgr.ChainParams())
	if _, err := mgr.Address(addr); err == nil {
		t.Fatalf("Address %s found in manager when it shouldn't", addr)
	}
	msgtx := tx.toMsgTx()

	pkScript, _ := txscript.PayToAddrScript(addr.(*dcrutil.AddressScriptHash))
	err := signMultiSigUTXO(mgr, msgtx, 0, pkScript, []RawSig{RawSig{}})

	TstCheckError(t, "", err, ErrTxSigning)
}
示例#11
0
// checkOutputsMatch checks that the outputs in the tx match the expected ones.
func checkOutputsMatch(t *testing.T, msgtx *wire.MsgTx, expected map[string]dcrutil.Amount) {
	// This is a bit convoluted because the index of the change output is randomized.
	for addrStr, v := range expected {
		addr, err := dcrutil.DecodeAddress(addrStr, &chaincfg.TestNetParams)
		if err != nil {
			t.Fatalf("Cannot decode address: %v", err)
		}
		pkScript, err := txscript.PayToAddrScript(addr)
		if err != nil {
			t.Fatalf("Cannot create pkScript: %v", err)
		}
		found := false
		for _, txout := range msgtx.TxOut {
			if reflect.DeepEqual(txout.PkScript, pkScript) && txout.Value == int64(v) {
				found = true
				break
			}
		}
		if !found {
			t.Fatalf("PkScript %v not found in msgtx.TxOut: %v", pkScript, msgtx.TxOut)
		}
	}
}
示例#12
0
// makeTx generates a transaction spending outputs to a single address.
func makeTx(params *chaincfg.Params,
	inputs []*extendedOutPoint,
	addr dcrutil.Address,
	txFee int64) (*wire.MsgTx, error) {
	mtx := wire.NewMsgTx()

	allInAmts := int64(0)
	for _, input := range inputs {
		txIn := wire.NewTxIn(input.op, []byte{})
		mtx.AddTxIn(txIn)
		allInAmts += input.amt
	}

	pkScript, err := txscript.PayToAddrScript(addr)
	if err != nil {
		return nil, err
	}
	txOut := wire.NewTxOut(allInAmts-txFee, pkScript)
	txOut.Version = txscript.DefaultScriptVersion
	mtx.AddTxOut(txOut)

	return mtx, nil

}
示例#13
0
// TestCheckTransactionStandard tests the checkTransactionStandard API.
func TestCheckTransactionStandard(t *testing.T) {
	// Create some dummy, but otherwise standard, data for transactions.
	prevOutHash, err := chainhash.NewHashFromStr("01")
	if err != nil {
		t.Fatalf("NewShaHashFromStr: unexpected error: %v", err)
	}
	dummyPrevOut := wire.OutPoint{Hash: *prevOutHash, Index: 1, Tree: 0}
	dummySigScript := bytes.Repeat([]byte{0x00}, 65)
	dummyTxIn := wire.TxIn{
		PreviousOutPoint: dummyPrevOut,
		Sequence:         wire.MaxTxInSequenceNum,
		ValueIn:          0,
		BlockHeight:      0,
		BlockIndex:       0,
		SignatureScript:  dummySigScript,
	}
	addrHash := [20]byte{0x01}
	addr, err := dcrutil.NewAddressPubKeyHash(addrHash[:],
		&chaincfg.TestNetParams, chainec.ECTypeSecp256k1)
	if err != nil {
		t.Fatalf("NewAddressPubKeyHash: unexpected error: %v", err)
	}
	dummyPkScript, err := txscript.PayToAddrScript(addr)
	if err != nil {
		t.Fatalf("PayToAddrScript: unexpected error: %v", err)
	}
	dummyTxOut := wire.TxOut{
		Value:    100000000, // 1 BTC
		Version:  0,
		PkScript: dummyPkScript,
	}

	tests := []struct {
		name       string
		tx         wire.MsgTx
		height     int64
		isStandard bool
		code       wire.RejectCode
	}{
		{
			name: "Typical pay-to-pubkey-hash transaction",
			tx: wire.MsgTx{
				Version:  1,
				TxIn:     []*wire.TxIn{&dummyTxIn},
				TxOut:    []*wire.TxOut{&dummyTxOut},
				LockTime: 0,
			},
			height:     300000,
			isStandard: true,
		},
		{
			name: "Transaction version too high",
			tx: wire.MsgTx{
				Version:  int32(wire.TxVersion + 1),
				TxIn:     []*wire.TxIn{&dummyTxIn},
				TxOut:    []*wire.TxOut{&dummyTxOut},
				LockTime: 0,
			},
			height:     300000,
			isStandard: false,
			code:       wire.RejectNonstandard,
		},
		{
			name: "Transaction is not finalized",
			tx: wire.MsgTx{
				Version: 1,
				TxIn: []*wire.TxIn{{
					PreviousOutPoint: dummyPrevOut,
					SignatureScript:  dummySigScript,
					Sequence:         0,
				}},
				TxOut:    []*wire.TxOut{&dummyTxOut},
				LockTime: 300001,
			},
			height:     300000,
			isStandard: false,
			code:       wire.RejectNonstandard,
		},
		{
			name: "Transaction size is too large",
			tx: wire.MsgTx{
				Version: 1,
				TxIn:    []*wire.TxIn{&dummyTxIn},
				TxOut: []*wire.TxOut{{
					Value: 0,
					PkScript: bytes.Repeat([]byte{0x00},
						maxStandardTxSize+1),
				}},
				LockTime: 0,
			},
			height:     300000,
			isStandard: false,
			code:       wire.RejectNonstandard,
		},
		{
			name: "Signature script size is too large",
			tx: wire.MsgTx{
				Version: 1,
				TxIn: []*wire.TxIn{{
					PreviousOutPoint: dummyPrevOut,
					SignatureScript: bytes.Repeat([]byte{0x00},
						maxStandardSigScriptSize+1),
					Sequence: wire.MaxTxInSequenceNum,
				}},
				TxOut:    []*wire.TxOut{&dummyTxOut},
				LockTime: 0,
			},
			height:     300000,
			isStandard: false,
			code:       wire.RejectNonstandard,
		},
		{
			name: "Signature script that does more than push data",
			tx: wire.MsgTx{
				Version: 1,
				TxIn: []*wire.TxIn{{
					PreviousOutPoint: dummyPrevOut,
					SignatureScript: []byte{
						txscript.OP_CHECKSIGVERIFY},
					Sequence: wire.MaxTxInSequenceNum,
				}},
				TxOut:    []*wire.TxOut{&dummyTxOut},
				LockTime: 0,
			},
			height:     300000,
			isStandard: false,
			code:       wire.RejectNonstandard,
		},
		{
			name: "Valid but non standard public key script",
			tx: wire.MsgTx{
				Version: 1,
				TxIn:    []*wire.TxIn{&dummyTxIn},
				TxOut: []*wire.TxOut{{
					Value:    100000000,
					PkScript: []byte{txscript.OP_TRUE},
				}},
				LockTime: 0,
			},
			height:     300000,
			isStandard: false,
			code:       wire.RejectNonstandard,
		},
		{
			name: "More than four nulldata outputs",
			tx: wire.MsgTx{
				Version: 1,
				TxIn:    []*wire.TxIn{&dummyTxIn},
				TxOut: []*wire.TxOut{{
					Value:    0,
					PkScript: []byte{txscript.OP_RETURN},
				}, {
					Value:    0,
					PkScript: []byte{txscript.OP_RETURN},
				}, {
					Value:    0,
					PkScript: []byte{txscript.OP_RETURN},
				}, {
					Value:    0,
					PkScript: []byte{txscript.OP_RETURN},
				}, {
					Value:    0,
					PkScript: []byte{txscript.OP_RETURN},
				}},
				LockTime: 0,
			},
			height:     300000,
			isStandard: false,
			code:       wire.RejectNonstandard,
		},
		{
			name: "Dust output",
			tx: wire.MsgTx{
				Version: 1,
				TxIn:    []*wire.TxIn{&dummyTxIn},
				TxOut: []*wire.TxOut{{
					Value:    0,
					PkScript: dummyPkScript,
				}},
				LockTime: 0,
			},
			height:     300000,
			isStandard: false,
			code:       wire.RejectDust,
		},
		{
			name: "One nulldata output with 0 amount (standard)",
			tx: wire.MsgTx{
				Version: 1,
				TxIn:    []*wire.TxIn{&dummyTxIn},
				TxOut: []*wire.TxOut{{
					Value:    0,
					PkScript: []byte{txscript.OP_RETURN},
				}},
				LockTime: 0,
			},
			height:     300000,
			isStandard: true,
		},
	}

	timeSource := blockchain.NewMedianTime()
	for _, test := range tests {
		// Ensure standardness is as expected.
		tx := dcrutil.NewTx(&test.tx)
		err := checkTransactionStandard(tx, stake.DetermineTxType(tx),
			test.height, timeSource, defaultMinRelayTxFee)
		if err == nil && test.isStandard {
			// Test passes since function returned standard for a
			// transaction which is intended to be standard.
			continue
		}
		if err == nil && !test.isStandard {
			t.Errorf("checkTransactionStandard (%s): standard when "+
				"it should not be", test.name)
			continue
		}
		if err != nil && test.isStandard {
			t.Errorf("checkTransactionStandard (%s): nonstandard "+
				"when it should not be: %v", test.name, err)
			continue
		}

		// Ensure error type is a TxRuleError inside of a RuleError.
		rerr, ok := err.(RuleError)
		if !ok {
			t.Errorf("checkTransactionStandard (%s): unexpected "+
				"error type - got %T", test.name, err)
			continue
		}
		txrerr, ok := rerr.Err.(TxRuleError)
		if !ok {
			t.Errorf("checkTransactionStandard (%s): unexpected "+
				"error type - got %T", test.name, rerr.Err)
			continue
		}

		// Ensure the reject code is the expected one.
		if txrerr.RejectCode != test.code {
			t.Errorf("checkTransactionStandard (%s): unexpected "+
				"error code - got %v, want %v", test.name,
				txrerr.RejectCode, test.code)
			continue
		}
	}
}
示例#14
0
// This example demonstrates how to use the Pool.StartWithdrawal method.
func Example_startWithdrawal() {
	// Create the address manager and votingpool DB namespace. See the example
	// for the Create() function for more info on how this is done.
	mgr, vpNamespace, tearDownFunc, err := exampleCreateMgrAndDBNamespace()
	if err != nil {
		fmt.Println(err)
		return
	}
	defer tearDownFunc()

	// Create a pool and a series. See the DepositAddress example for more info
	// on how this is done.
	pool, seriesID, err := exampleCreatePoolAndSeries(mgr, vpNamespace)
	if err != nil {
		fmt.Println(err)
		return
	}

	// Unlock the manager
	if err := mgr.Unlock(privPassphrase); err != nil {
		fmt.Println(err)
		return
	}
	defer mgr.Lock()

	addr, _ := dcrutil.DecodeAddress("1MirQ9bwyQcGVJPwKUgapu5ouK2E2Ey4gX", mgr.ChainParams())
	pkScript, _ := txscript.PayToAddrScript(addr)
	requests := []votingpool.OutputRequest{
		votingpool.OutputRequest{
			PkScript:    pkScript,
			Address:     addr,
			Amount:      1e6,
			Server:      "server-id",
			Transaction: 123},
	}
	changeStart, err := pool.ChangeAddress(seriesID, votingpool.Index(0))
	if err != nil {
		fmt.Println(err)
		return
	}
	// This is only needed because we have not used any deposit addresses from
	// the series, and we cannot create a WithdrawalAddress for an unused
	// branch/idx pair.
	if err = pool.EnsureUsedAddr(seriesID, votingpool.Branch(1), votingpool.Index(0)); err != nil {
		fmt.Println(err)
		return
	}
	startAddr, err := pool.WithdrawalAddress(seriesID, votingpool.Branch(1), votingpool.Index(0))
	if err != nil {
		fmt.Println(err)
		return
	}
	lastSeriesID := seriesID
	dustThreshold := dcrutil.Amount(1e4)
	currentBlock := int32(19432)
	roundID := uint32(0)
	txstore, tearDownFunc, err := exampleCreateTxStore()
	if err != nil {
		fmt.Println(err)
		return
	}
	_, err = pool.StartWithdrawal(
		roundID, requests, *startAddr, lastSeriesID, *changeStart, txstore, currentBlock,
		dustThreshold)
	if err != nil {
		fmt.Println(err)
	}

	// Output:
	//
}
示例#15
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 := chainec.Secp256k1.PrivKeyFromBytes(privKeyBytes)
	pubKeyHash := dcrutil.Hash160(pubKey.SerializeCompressed())
	addr, err := dcrutil.NewAddressPubKeyHash(pubKeyHash,
		&chaincfg.MainNetParams, chainec.ECTypeSecp256k1)
	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 DCR.
	originTx := wire.NewMsgTx()
	prevOut := wire.NewOutPoint(&chainhash.Hash{}, ^uint32(0), dcrutil.TxTreeRegular)
	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, dcrutil.TxTreeRegular)
	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 dcrutil.Address) (chainec.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, secp)
	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.ScriptDiscourageUpgradableNops
	vm, err := txscript.NewEngine(originTx.TxOut[0].PkScript, redeemTx, 0,
		flags, 0)
	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
}
示例#16
0
func TestLimitAndSkipFetchTxsForAddr(t *testing.T) {
	testDb, err := setUpTestDb(t, "tstdbtxaddr")
	if err != nil {
		t.Errorf("Failed to open test database %v", err)
		return
	}
	defer testDb.cleanUpFunc()
	_, err = testDb.db.InsertBlock(testDb.blocks[0])
	if err != nil {
		t.Fatalf("failed to insert initial block")
	}
	// Insert a block with some fake test transactions. The block will have
	// 10 copies of a fake transaction involving same address.
	addrString := "DsZEAobx6qJ7K2qaHZBA2vBn66Nor8KYAKk"
	targetAddr, err := dcrutil.DecodeAddress(addrString, &chaincfg.MainNetParams)
	if err != nil {
		t.Fatalf("Unable to decode test address: %v", err)
	}
	outputScript, err := txscript.PayToAddrScript(targetAddr)
	if err != nil {
		t.Fatalf("Unable make test pkScript %v", err)
	}
	fakeTxOut := wire.NewTxOut(10, outputScript)
	var emptyHash chainhash.Hash
	fakeHeader := wire.NewBlockHeader(0, &emptyHash, &emptyHash, &emptyHash, 1, [6]byte{}, 1, 1, 1, 1, 1, 1, 1, 1, 1, [36]byte{})
	msgBlock := wire.NewMsgBlock(fakeHeader)
	for i := 0; i < 10; i++ {
		mtx := wire.NewMsgTx()
		mtx.AddTxOut(fakeTxOut)
		msgBlock.AddTransaction(mtx)
	}
	lastBlock := testDb.blocks[0]
	msgBlock.Header.PrevBlock = *lastBlock.Sha()
	// Insert the test block into the DB.
	testBlock := dcrutil.NewBlock(msgBlock)
	newheight, err := testDb.db.InsertBlock(testBlock)
	if err != nil {
		t.Fatalf("Unable to insert block into db: %v", err)
	}

	// Create and insert an address index for out test addr.
	txLoc, _, _ := testBlock.TxLoc()
	index := make(database.BlockAddrIndex, len(txLoc))
	for i := range testBlock.Transactions() {
		var hash160 [ripemd160.Size]byte
		scriptAddr := targetAddr.ScriptAddress()
		copy(hash160[:], scriptAddr[:])
		txAddrIndex := &database.TxAddrIndex{
			Hash160:  hash160,
			Height:   uint32(newheight),
			TxOffset: uint32(txLoc[i].TxStart),
			TxLen:    uint32(txLoc[i].TxLen),
		}

		index[i] = txAddrIndex
	}
	blkSha := testBlock.Sha()
	err = testDb.db.UpdateAddrIndexForBlock(blkSha, newheight, index)
	if err != nil {
		t.Fatalf("UpdateAddrIndexForBlock: failed to index"+
			" addrs for block #%d (%s) "+
			"err %v", newheight, blkSha, err)
		return
	}

	// Try skipping the first 4 results, should get 6 in return.
	txReply, err := testDb.db.FetchTxsForAddr(targetAddr, 4, 100000)
	if err != nil {
		t.Fatalf("Unable to fetch transactions for address: %v", err)
	}
	if len(txReply) != 6 {
		t.Fatalf("Did not correctly skip forward in txs for address reply"+
			" got %v txs, expected %v", len(txReply), 6)
	}

	// Limit the number of results to 3.
	txReply, err = testDb.db.FetchTxsForAddr(targetAddr, 0, 3)
	if err != nil {
		t.Fatalf("Unable to fetch transactions for address: %v", err)
	}
	if len(txReply) != 3 {
		t.Fatalf("Did not correctly limit in txs for address reply"+
			" got %v txs, expected %v", len(txReply), 3)
	}

	// Skip 1, limit 5.
	txReply, err = testDb.db.FetchTxsForAddr(targetAddr, 1, 5)
	if err != nil {
		t.Fatalf("Unable to fetch transactions for address: %v", err)
	}
	if len(txReply) != 5 {
		t.Fatalf("Did not correctly limit in txs for address reply"+
			" got %v txs, expected %v", len(txReply), 5)
	}
}
示例#17
0
// TestPayToAddrScript ensures the PayToAddrScript function generates the
// correct scripts for the various types of addresses.
func TestPayToAddrScript(t *testing.T) {
	t.Parallel()

	// 1MirQ9bwyQcGVJPwKUgapu5ouK2E2Ey4gX
	p2pkhMain, err := dcrutil.NewAddressPubKeyHash(decodeHex("e34cce70c863"+
		"73273efcc54ce7d2a491bb4a0e84"), &chaincfg.MainNetParams, secp)
	if err != nil {
		t.Errorf("Unable to create public key hash address: %v", err)
		return
	}

	// Taken from transaction:
	// b0539a45de13b3e0403909b8bd1a555b8cbe45fd4e3f3fda76f3a5f52835c29d
	p2shMain, _ := dcrutil.NewAddressScriptHashFromHash(decodeHex("e8c300"+
		"c87986efa84c37c0519929019ef86eb5b4"), &chaincfg.MainNetParams)
	if err != nil {
		t.Errorf("Unable to create script hash address: %v", err)
		return
	}

	//  mainnet p2pk 13CG6SJ3yHUXo4Cr2RY4THLLJrNFuG3gUg
	p2pkCompressedMain, err := dcrutil.NewAddressSecpPubKey(decodeHex("02192d74"+
		"d0cb94344c9569c2e77901573d8d7903c3ebec3a957724895dca52c6b4"),
		&chaincfg.MainNetParams)
	if err != nil {
		t.Errorf("Unable to create pubkey address (compressed): %v",
			err)
		return
	}
	p2pkCompressed2Main, err := dcrutil.NewAddressSecpPubKey(decodeHex("03b0bd"+
		"634234abbb1ba1e986e884185c61cf43e001f9137f23c2c409273eb16e65"),
		&chaincfg.MainNetParams)
	if err != nil {
		t.Errorf("Unable to create pubkey address (compressed 2): %v",
			err)
		return
	}

	p2pkUncompressedMain, err := dcrutil.NewAddressSecpPubKey(decodeHex("0411db"+
		"93e1dcdb8a016b49840f8c53bc1eb68a382e97b1482ecad7b148a6909a5cb2"+
		"e0eaddfb84ccf9744464f82e160bfa9b8b64f9d4c03f999b8643f656b412a3"),
		&chaincfg.MainNetParams)
	if err != nil {
		t.Errorf("Unable to create pubkey address (uncompressed): %v",
			err)
		return
	}

	tests := []struct {
		in       dcrutil.Address
		expected string
		err      error
	}{
		// pay-to-pubkey-hash address on mainnet 0
		{
			p2pkhMain,
			"DUP HASH160 DATA_20 0xe34cce70c86373273efcc54ce7d2a4" +
				"91bb4a0e8488 CHECKSIG",
			nil,
		},
		// pay-to-script-hash address on mainnet 1
		{
			p2shMain,
			"HASH160 DATA_20 0xe8c300c87986efa84c37c0519929019ef8" +
				"6eb5b4 EQUAL",
			nil,
		},
		// pay-to-pubkey address on mainnet. compressed key. 2
		{
			p2pkCompressedMain,
			"DATA_33 0x02192d74d0cb94344c9569c2e77901573d8d7903c3" +
				"ebec3a957724895dca52c6b4 CHECKSIG",
			nil,
		},
		// pay-to-pubkey address on mainnet. compressed key (other way). 3
		{
			p2pkCompressed2Main,
			"DATA_33 0x03b0bd634234abbb1ba1e986e884185c61cf43e001" +
				"f9137f23c2c409273eb16e65 CHECKSIG",
			nil,
		},
		// pay-to-pubkey address on mainnet. for decred this would
		// be uncompressed, but standard for decred is 33 byte
		// compressed public keys.
		{
			p2pkUncompressedMain,
			"DATA_33 0x0311db93e1dcdb8a016b49840f8c53bc1eb68a382e97b" +
				"1482ecad7b148a6909a5cac",
			nil,
		},

		// Supported address types with nil pointers.
		{(*dcrutil.AddressPubKeyHash)(nil), "", txscript.ErrUnsupportedAddress},
		{(*dcrutil.AddressScriptHash)(nil), "", txscript.ErrUnsupportedAddress},
		{(*dcrutil.AddressSecpPubKey)(nil), "", txscript.ErrUnsupportedAddress},

		// Unsupported address type.
		{&bogusAddress{}, "", txscript.ErrUnsupportedAddress},
	}

	t.Logf("Running %d tests", len(tests))
	for i, test := range tests {
		pkScript, err := txscript.PayToAddrScript(test.in)
		if err != test.err {
			t.Errorf("PayToAddrScript #%d unexpected error - "+
				"got %v, want %v", i, err, test.err)
			continue
		}

		expected := mustParseShortForm(test.expected)
		if !bytes.Equal(pkScript, expected) {
			t.Errorf("PayToAddrScript #%d got: %x\nwant: %x",
				i, pkScript, expected)
			continue
		}
	}
}
示例#18
0
// deserializeWithdrawal deserializes the given byte slice into a dbWithdrawalRow,
// converts it into an withdrawalInfo and returns it. This function must run
// with the address manager unlocked.
func deserializeWithdrawal(p *Pool, serialized []byte) (*withdrawalInfo, error) {
	var row dbWithdrawalRow
	if err := gob.NewDecoder(bytes.NewReader(serialized)).Decode(&row); err != nil {
		return nil, newError(ErrWithdrawalStorage, "cannot deserialize withdrawal information",
			err)
	}
	wInfo := &withdrawalInfo{
		lastSeriesID:  row.LastSeriesID,
		dustThreshold: row.DustThreshold,
	}
	chainParams := p.Manager().ChainParams()
	wInfo.requests = make([]OutputRequest, len(row.Requests))
	// A map of requests indexed by OutBailmentID; needed to populate
	// WithdrawalStatus.Outputs later on.
	requestsByOID := make(map[OutBailmentID]OutputRequest)
	for i, req := range row.Requests {
		addr, err := dcrutil.DecodeAddress(req.Addr, chainParams)
		if err != nil {
			return nil, newError(ErrWithdrawalStorage,
				"cannot deserialize addr for requested output", err)
		}
		pkScript, err := txscript.PayToAddrScript(addr)
		if err != nil {
			return nil, newError(ErrWithdrawalStorage, "invalid addr for requested output", err)
		}
		request := OutputRequest{
			Address:     addr,
			Amount:      req.Amount,
			PkScript:    pkScript,
			Server:      req.Server,
			Transaction: req.Transaction,
		}
		wInfo.requests[i] = request
		requestsByOID[request.outBailmentID()] = request
	}
	startAddr := row.StartAddress
	wAddr, err := p.WithdrawalAddress(startAddr.SeriesID, startAddr.Branch, startAddr.Index)
	if err != nil {
		return nil, newError(ErrWithdrawalStorage, "cannot deserialize startAddress", err)
	}
	wInfo.startAddress = *wAddr

	cAddr, err := p.ChangeAddress(row.ChangeStart.SeriesID, row.ChangeStart.Index)
	if err != nil {
		return nil, newError(ErrWithdrawalStorage, "cannot deserialize changeStart", err)
	}
	wInfo.changeStart = *cAddr

	// TODO: Copy over row.Status.nextInputAddr. Not done because StartWithdrawal
	// does not update that yet.
	nextChangeAddr := row.Status.NextChangeAddr
	cAddr, err = p.ChangeAddress(nextChangeAddr.SeriesID, nextChangeAddr.Index)
	if err != nil {
		return nil, newError(ErrWithdrawalStorage,
			"cannot deserialize nextChangeAddress for withdrawal", err)
	}
	wInfo.status = WithdrawalStatus{
		nextChangeAddr: *cAddr,
		fees:           row.Status.Fees,
		outputs:        make(map[OutBailmentID]*WithdrawalOutput, len(row.Status.Outputs)),
		sigs:           row.Status.Sigs,
		transactions:   make(map[Ntxid]changeAwareTx, len(row.Status.Transactions)),
	}
	for oid, output := range row.Status.Outputs {
		outpoints := make([]OutBailmentOutpoint, len(output.Outpoints))
		for i, outpoint := range output.Outpoints {
			outpoints[i] = OutBailmentOutpoint{
				ntxid:  outpoint.Ntxid,
				index:  outpoint.Index,
				amount: outpoint.Amount,
			}
		}
		wInfo.status.outputs[oid] = &WithdrawalOutput{
			request:   requestsByOID[output.OutBailmentID],
			status:    output.Status,
			outpoints: outpoints,
		}
	}
	for ntxid, tx := range row.Status.Transactions {
		msgtx := wire.NewMsgTx()
		if err := msgtx.Deserialize(bytes.NewBuffer(tx.SerializedMsgTx)); err != nil {
			return nil, newError(ErrWithdrawalStorage, "cannot deserialize transaction", err)
		}
		wInfo.status.transactions[ntxid] = changeAwareTx{
			MsgTx:     msgtx,
			changeIdx: tx.ChangeIdx,
		}
	}
	return wInfo, nil
}