Example #1
0
// prepare a signed transaction
func make_signed_tx() {
	// Make an empty transaction
	tx := new(btc.Tx)
	tx.Version = 1
	tx.Lock_time = 0

	// Select as many inputs as we need to pay the full amount (with the fee)
	var btcsofar uint64
	for i := range unspentOuts {
		if unspentOuts[i].key == nil {
			continue
		}
		uo := getUO(&unspentOuts[i].TxPrevOut)
		// add the input to our transaction:
		tin := new(btc.TxIn)
		tin.Input = unspentOuts[i].TxPrevOut
		tin.Sequence = uint32(*sequence)
		tx.TxIn = append(tx.TxIn, tin)

		btcsofar += uo.Value
		unspentOuts[i].spent = true
		if !*useallinputs && (btcsofar >= spendBtc+feeBtc) {
			break
		}
	}
	if btcsofar < (spendBtc + feeBtc) {
		fmt.Println("ERROR: You have", btc.UintToBtc(btcsofar), "BTC, but you need",
			btc.UintToBtc(spendBtc+feeBtc), "BTC for the transaction")
		cleanExit(1)
	}
	changeBtc = btcsofar - (spendBtc + feeBtc)
	if *verbose {
		fmt.Printf("Spending %d out of %d outputs...\n", len(tx.TxIn), len(unspentOuts))
	}

	// Build transaction outputs:
	for o := range sendTo {
		outs, er := btc.NewSpendOutputs(sendTo[o].addr, sendTo[o].amount, testnet)
		if er != nil {
			fmt.Println("ERROR:", er.Error())
			cleanExit(1)
		}
		tx.TxOut = append(tx.TxOut, outs...)
	}

	if changeBtc > 0 {
		// Add one more output (with the change)
		chad := get_change_addr()
		if *verbose {
			fmt.Println("Sending change", changeBtc, "to", chad.String())
		}
		outs, er := btc.NewSpendOutputs(chad, changeBtc, testnet)
		if er != nil {
			fmt.Println("ERROR:", er.Error())
			cleanExit(1)
		}
		tx.TxOut = append(tx.TxOut, outs...)
	}

	if *message != "" {
		// Add NULL output with an arbitrary message
		scr := new(bytes.Buffer)
		scr.WriteByte(0x6a) // OP_RETURN
		btc.WritePutLen(scr, uint32(len(*message)))
		scr.Write([]byte(*message))
		tx.TxOut = append(tx.TxOut, &btc.TxOut{Value: 0, Pk_script: scr.Bytes()})
	}

	signed := sign_tx(tx)
	write_tx_file(tx)

	if apply2bal && signed {
		apply_to_balance(tx)
	}
}
Example #2
0
// prepare a signed transaction
func make_signed_tx() {
	// Make an empty transaction
	tx := new(btc.Tx)
	tx.Version = 1
	tx.Lock_time = 0

	// Select as many inputs as we need to pay the full amount (with the fee)
	var btcsofar uint64
	for inpcnt := 0; inpcnt < len(unspentOuts); inpcnt++ {
		uo := UO(unspentOuts[inpcnt])
		// add the input to our transaction:
		tin := new(btc.TxIn)
		tin.Input = *unspentOuts[inpcnt]
		tin.Sequence = 0xffffffff
		tx.TxIn = append(tx.TxIn, tin)

		btcsofar += uo.Value
		if !*useallinputs && (btcsofar >= spendBtc+feeBtc) {
			break
		}
	}
	changeBtc = btcsofar - (spendBtc + feeBtc)
	if *verbose {
		fmt.Printf("Spending %d out of %d outputs...\n", len(tx.TxIn), len(unspentOuts))
	}

	// Build transaction outputs:
	for o := range sendTo {
		outs, er := btc.NewSpendOutputs(sendTo[o].addr, sendTo[o].amount, testnet)
		if er != nil {
			fmt.Println("ERROR:", er.Error())
			os.Exit(1)
		}
		tx.TxOut = append(tx.TxOut, outs...)
	}

	if changeBtc > 0 {
		// Add one more output (with the change)
		chad := get_change_addr()
		if *verbose {
			fmt.Println("Sending change", changeBtc, "to", chad.String())
		}
		outs, er := btc.NewSpendOutputs(chad, changeBtc, testnet)
		if er != nil {
			fmt.Println("ERROR:", er.Error())
			os.Exit(1)
		}
		tx.TxOut = append(tx.TxOut, outs...)
	}

	if *message != "" {
		// Add NULL output with an arbitrary message
		scr := new(bytes.Buffer)
		scr.WriteByte(0x6a) // OP_RETURN
		btc.WritePutLen(scr, uint32(len(*message)))
		scr.Write([]byte(*message))
		tx.TxOut = append(tx.TxOut, &btc.TxOut{Value: 0, Pk_script: scr.Bytes()})
	}

	if *hashes {
		dump_hashes_to_sign(tx)
	} else {
		signed := sign_tx(tx)
		write_tx_file(tx)

		if apply2bal && signed {
			apply_to_balance(tx)
		}
	}
}
Example #3
0
func VerifyTxScript(pkScr []byte, amount uint64, i int, tx *btc.Tx, ver_flags uint32) (result bool) {
	if VerifyConsensus != nil {
		defer func() {
			// We call CompareToConsensus inside another function to wait for final "result"
			VerifyConsensus(pkScr, amount, i, tx, ver_flags, result)
		}()
	}

	sigScr := tx.TxIn[i].ScriptSig

	if (ver_flags&VER_SIGPUSHONLY) != 0 && !btc.IsPushOnly(sigScr) {
		if DBG_ERR {
			fmt.Println("Not push only")
		}
		return false
	}

	if DBG_SCR {
		fmt.Println("VerifyTxScript", tx.Hash.String(), i+1, "/", len(tx.TxIn))
		fmt.Println("sigScript:", hex.EncodeToString(sigScr[:]))
		fmt.Println("_pkScript:", hex.EncodeToString(pkScr))
		fmt.Printf("flagz:%x\n", ver_flags)
	}

	var stack, stackCopy scrStack
	if !evalScript(sigScr, amount, &stack, tx, i, ver_flags, SIGVERSION_BASE) {
		if DBG_ERR {
			if tx != nil {
				fmt.Println("VerifyTxScript", tx.Hash.String(), i+1, "/", len(tx.TxIn))
			}
			fmt.Println("sigScript failed :", hex.EncodeToString(sigScr[:]))
			fmt.Println("pkScript:", hex.EncodeToString(pkScr[:]))
		}
		return
	}
	if DBG_SCR {
		fmt.Println("\nsigScr verified OK")
		//stack.print()
		fmt.Println()
	}

	if (ver_flags&VER_P2SH) != 0 && stack.size() > 0 {
		// copy the stack content to stackCopy
		stackCopy.copy_from(&stack)
	}

	if !evalScript(pkScr, amount, &stack, tx, i, ver_flags, SIGVERSION_BASE) {
		if DBG_SCR {
			fmt.Println("* pkScript failed :", hex.EncodeToString(pkScr[:]))
			fmt.Println("* VerifyTxScript", tx.Hash.String(), i+1, "/", len(tx.TxIn))
			fmt.Println("* sigScript:", hex.EncodeToString(sigScr[:]))
		}
		return
	}

	if stack.size() == 0 {
		if DBG_SCR {
			fmt.Println("* stack empty after executing scripts:", hex.EncodeToString(pkScr[:]))
		}
		return
	}

	if !stack.topBool(-1) {
		if DBG_SCR {
			fmt.Println("* FALSE on stack after executing scripts:", hex.EncodeToString(pkScr[:]))
		}
		return
	}

	// Bare witness programs
	var witnessversion int
	var witnessprogram []byte
	var hadWitness bool
	var witness witness_ctx

	if (ver_flags & VER_WITNESS) != 0 {
		if tx.SegWit != nil {
			for _, wd := range tx.SegWit[i] {
				witness.stack.push(wd)
			}
		}

		witnessversion, witnessprogram = btc.IsWitnessProgram(pkScr)
		if DBG_SCR {
			fmt.Println("------------witnessversion:", witnessversion, "   witnessprogram:", hex.EncodeToString(witnessprogram))
		}
		if witnessprogram != nil {
			hadWitness = true
			if len(sigScr) != 0 {
				if DBG_ERR {
					fmt.Println("SCRIPT_ERR_WITNESS_MALLEATED")
				}
				return
			}
			if !VerifyWitnessProgram(&witness, amount, tx, i, witnessversion, witnessprogram, ver_flags) {
				if DBG_ERR {
					fmt.Println("VerifyWitnessProgram failed A")
				}
				return false
			}
			// Bypass the cleanstack check at the end. The actual stack is obviously not clean
			// for witness programs.
			stack.resize(1)
		} else {
			if DBG_SCR {
				fmt.Println("No witness program")
			}
		}
	} else {
		if DBG_SCR {
			fmt.Println("Witness flag off")
		}
	}

	// Additional validation for spend-to-script-hash transactions:
	if (ver_flags&VER_P2SH) != 0 && btc.IsPayToScript(pkScr) {
		if DBG_SCR {
			fmt.Println()
			fmt.Println()
			fmt.Println(" ******************* Looks like P2SH script ********************* ")
			stack.print()
		}

		if DBG_SCR {
			fmt.Println("sigScr len", len(sigScr), hex.EncodeToString(sigScr))
		}
		if !btc.IsPushOnly(sigScr) {
			if DBG_ERR {
				fmt.Println("P2SH is not push only")
			}
			return
		}

		// Restore stack.
		stack = stackCopy

		pubKey2 := stack.pop()
		if DBG_SCR {
			fmt.Println("pubKey2:", hex.EncodeToString(pubKey2))
		}

		if !evalScript(pubKey2, amount, &stack, tx, i, ver_flags, SIGVERSION_BASE) {
			if DBG_ERR {
				fmt.Println("P2SH extra verification failed")
			}
			return
		}

		if stack.size() == 0 {
			if DBG_SCR {
				fmt.Println("* P2SH stack empty after executing script:", hex.EncodeToString(pubKey2))
			}
			return
		}

		if !stack.topBool(-1) {
			if DBG_SCR {
				fmt.Println("* FALSE on stack after executing P2SH script:", hex.EncodeToString(pubKey2))
			}
			return
		}

		if (ver_flags & VER_WITNESS) != 0 {
			witnessversion, witnessprogram = btc.IsWitnessProgram(pubKey2)
			if DBG_SCR {
				fmt.Println("============witnessversion:", witnessversion, "   witnessprogram:", hex.EncodeToString(witnessprogram))
			}
			if witnessprogram != nil {
				hadWitness = true
				bt := new(bytes.Buffer)
				btc.WritePutLen(bt, uint32(len(pubKey2)))
				bt.Write(pubKey2)
				if !bytes.Equal(sigScr, bt.Bytes()) {
					if DBG_ERR {
						fmt.Println(hex.EncodeToString(sigScr))
						fmt.Println(hex.EncodeToString(bt.Bytes()))
						fmt.Println("SCRIPT_ERR_WITNESS_MALLEATED_P2SH")
					}
					return
				}
				if !VerifyWitnessProgram(&witness, amount, tx, i, witnessversion, witnessprogram, ver_flags) {
					if DBG_ERR {
						fmt.Println("VerifyWitnessProgram failed B")
					}
					return false
				}
				// Bypass the cleanstack check at the end. The actual stack is obviously not clean
				// for witness programs.
				stack.resize(1)
			}
		}
	}

	if (ver_flags & VER_CLEANSTACK) != 0 {
		if (ver_flags & VER_P2SH) == 0 {
			panic("VER_CLEANSTACK without VER_P2SH")
		}
		if DBG_SCR {
			fmt.Println("stack size", stack.size())
		}
		if stack.size() != 1 {
			if DBG_ERR {
				fmt.Println("Stack not clean")
			}
			return
		}
	}

	if (ver_flags & VER_WITNESS) != 0 {
		// We can't check for correct unexpected witness data if P2SH was off, so require
		// that WITNESS implies P2SH. Otherwise, going from WITNESS->P2SH+WITNESS would be
		// possible, which is not a softfork.
		if (ver_flags & VER_P2SH) == 0 {
			panic("VER_WITNESS must be used with P2SH")
		}
		if !hadWitness && !witness.IsNull() {
			if DBG_ERR {
				fmt.Println("SCRIPT_ERR_WITNESS_UNEXPECTED", len(tx.SegWit))
			}
			return
		}
	}

	result = true
	return true
}