示例#1
0
// apply the chnages to the balance folder
func apply_to_balance(tx *btc.Tx) {
	f, _ := os.Create("balance/unspent.txt")
	if f != nil {
		// append new outputs at the end of unspentOuts
		ioutil.WriteFile("balance/"+tx.Hash.String()+".tx", tx.Serialize(), 0600)

		fmt.Println("Adding", len(tx.TxOut), "new output(s) to the balance/ folder...")
		for out := range tx.TxOut {
			if k := pkscr_to_key(tx.TxOut[out].Pk_script); k != nil {
				uns := new(unspRec)
				uns.key = k
				uns.TxPrevOut.Hash = tx.Hash.Hash
				uns.TxPrevOut.Vout = uint32(out)
				uns.label = fmt.Sprint("# ", btc.UintToBtc(tx.TxOut[out].Value), " BTC @ ", k.BtcAddr.String())
				//stealth bool TODO: maybe we can fix it...
				unspentOuts = append(unspentOuts, uns)
			}
		}

		for j := range unspentOuts {
			if !unspentOuts[j].spent {
				fmt.Fprintln(f, unspentOuts[j].String())
			}
		}
		f.Close()
	} else {
		println("ERROR: Cannot create balance/unspent.txt")
	}
}
示例#2
0
文件: signtx.go 项目: vancsj/gocoin
func write_tx_file(tx *btc.Tx) {
	signedrawtx := tx.Serialize()
	tx.Hash = btc.NewSha2Hash(signedrawtx)

	hs := tx.Hash.String()
	fmt.Println("TxID", hs)

	f, _ := os.Create(hs[:8] + ".txt")
	if f != nil {
		f.Write([]byte(hex.EncodeToString(signedrawtx)))
		f.Close()
		fmt.Println("Transaction data stored in", hs[:8]+".txt")
	}
}
示例#3
0
func consensus_verify_script(pkScr []byte, i int, tx *btc.Tx, ver_flags uint32) bool {
	txTo := tx.Serialize()

	var pkscr_ptr, pkscr_len uintptr // default to 0/null
	if pkScr != nil {
		pkscr_ptr = uintptr(unsafe.Pointer(&pkScr[0]))
		pkscr_len = uintptr(len(pkScr))
	}
	r1, _, _ := syscall.Syscall9(bitcoinconsensus_verify_script.Addr(), 7,
		pkscr_ptr, pkscr_len,
		uintptr(unsafe.Pointer(&txTo[0])), uintptr(len(txTo)),
		uintptr(i), uintptr(ver_flags), 0, 0, 0)

	return r1 == 1
}
示例#4
0
文件: multisig.go 项目: liudch/gocoin
// reorder signatures to meet order of the keys
// remove signatuers made by the same keys
// remove exessive signatures (keeps transaction size down)
func multisig_reorder(tx *btc.Tx) (all_signed bool) {
	all_signed = true
	for i := range tx.TxIn {
		ms, _ := btc.NewMultiSigFromScript(tx.TxIn[i].ScriptSig)
		if ms == nil {
			continue
		}
		hash := tx.SignatureHash(ms.P2SH(), i, btc.SIGHASH_ALL)

		var sigs []*btc.Signature
		for ki := range ms.PublicKeys {
			var sig *btc.Signature
			for si := range ms.Signatures {
				if btc.EcdsaVerify(ms.PublicKeys[ki], ms.Signatures[si].Bytes(), hash) {
					//fmt.Println("Key number", ki, "has signature number", si)
					sig = ms.Signatures[si]
					break
				}
			}
			if sig != nil {
				sigs = append(sigs, sig)
			} else if *verbose {
				fmt.Println("WARNING: Key number", ki, "has no matching signature")
			}

			if !*allowextramsigns && uint(len(sigs)) >= ms.SigsNeeded {
				break
			}
		}

		if *verbose {
			if len(ms.Signatures) > len(sigs) {
				fmt.Println("WARNING: Some signatures are obsolete and will be removed", len(ms.Signatures), "=>", len(sigs))
			} else if len(ms.Signatures) < len(sigs) {
				fmt.Println("It appears that same key is re-used.", len(sigs)-len(ms.Signatures), "more signatures were added")
			}
		}

		ms.Signatures = sigs
		tx.TxIn[i].ScriptSig = ms.Bytes()

		if len(sigs) < int(ms.SigsNeeded) {
			all_signed = false
		}
	}
	return
}
示例#5
0
文件: mining.go 项目: piotrnar/gocoin
// return miner ID of the given coinbase transaction
func TxMiner(cbtx *btc.Tx) (string, int) {
	txdat := cbtx.Serialize()
	for i, m := range MinerIds {
		if bytes.Equal(m.Tag, []byte("_p2pool_")) { // P2Pool
			if len(cbtx.TxOut) > 10 &&
				bytes.Equal(cbtx.TxOut[len(cbtx.TxOut)-1].Pk_script[:2], []byte{0x6A, 0x28}) {
				return m.Name, i
			}
		} else if bytes.Contains(txdat, m.Tag) {
			return m.Name, i
		}
	}

	adr := btc.NewAddrFromPkScript(cbtx.TxOut[0].Pk_script, Testnet)
	if adr != nil {
		return adr.String(), -1
	}

	return "", -1
}
示例#6
0
func mk_spend_tx(input_tx *btc.Tx, sig_scr []byte, witness [][]byte) (output_tx *btc.Tx) {
	output_tx = new(btc.Tx)
	output_tx.Version = 1
	output_tx.TxIn = []*btc.TxIn{&btc.TxIn{Input: btc.TxPrevOut{Hash: btc.Sha2Sum(input_tx.Serialize()), Vout: 0},
		ScriptSig: sig_scr, Sequence: 0xffffffff}}
	output_tx.TxOut = []*btc.TxOut{&btc.TxOut{Value: input_tx.TxOut[0].Value}}
	// Lock_time = 0

	if len(witness) > 0 {
		output_tx.SegWit = make([][][]byte, 1)
		output_tx.SegWit[0] = witness
		if DBG_SCR {
			println("tx has", len(witness), "ws")
			for xx := range witness {
				println("", xx, hex.EncodeToString(witness[xx]))
			}
		}
	}
	output_tx.SetHash(output_tx.Serialize())
	return
}
示例#7
0
func check_consensus(pkScr []byte, amount uint64, i int, tx *btc.Tx, ver_flags uint32, result bool) {
	var tmp []byte
	if len(pkScr) != 0 {
		tmp = make([]byte, len(pkScr))
		copy(tmp, pkScr)
	}
	tx_raw := tx.Raw
	if tx_raw == nil {
		tx_raw = tx.Serialize()
	}
	go func(pkScr []byte, txTo []byte, i int, ver_flags uint32, result bool) {
		var pkscr_ptr, pkscr_len uintptr // default to 0/null
		if pkScr != nil {
			pkscr_ptr = uintptr(unsafe.Pointer(&pkScr[0]))
			pkscr_len = uintptr(len(pkScr))
		}
		r1, _, _ := syscall.Syscall9(bitcoinconsensus_verify_script_with_amount.Addr(), 8,
			pkscr_ptr, pkscr_len, uintptr(amount),
			uintptr(unsafe.Pointer(&txTo[0])), uintptr(len(txTo)),
			uintptr(i), uintptr(ver_flags), 0, 0)

		res := r1 == 1
		atomic.AddUint64(&ConsensusChecks, 1)
		if !result {
			atomic.AddUint64(&ConsensusExpErr, 1)
		}
		if res != result {
			atomic.AddUint64(&ConsensusErrors, 1)
			common.CountSafe("TxConsensusERR")
			mut.Lock()
			println("Compare to consensus failed!")
			println("Gocoin:", result, "   ConsLIB:", res)
			println("pkScr", hex.EncodeToString(pkScr))
			println("txTo", hex.EncodeToString(txTo))
			println("amount:", amount, "  input_idx:", i, "  ver_flags:", ver_flags)
			println()
			mut.Unlock()
		}
	}(tmp, tx_raw, i, ver_flags, result)
}
示例#8
0
文件: signtx.go 项目: vancsj/gocoin
// dump hashes to be signed
func dump_hashes_to_sign(tx *btc.Tx) {
	for in := range tx.TxIn {
		uo := UO(unspentOuts[in])
		if uo == nil {
			println("Unknown content of unspent input number", in)
			os.Exit(1)
		}
		var pubad *btc.BtcAddr
		if litecoin {
			pubad = ltc.NewAddrFromPkScript(uo.Pk_script, testnet)
		} else {
			pubad = btc.NewAddrFromPkScript(uo.Pk_script, testnet)
		}
		if pubad != nil {
			hash := tx.SignatureHash(uo.Pk_script, in, btc.SIGHASH_ALL)
			fmt.Printf("Input #%d:\n\tHash : %s\n\tAddr : %s\n", in, hex.EncodeToString(hash), pubad.String())
		} else {
			println("Cannot decode pkscript of unspent input number", in)
			os.Exit(1)
		}
	}
}
示例#9
0
文件: signtx.go 项目: vancsj/gocoin
// apply the chnages to the balance folder
func apply_to_balance(tx *btc.Tx) {
	fmt.Println("Applying the transaction to the balance/ folder...")
	f, _ := os.Create("balance/unspent.txt")
	if f != nil {
		for j := 0; j < len(unspentOuts); j++ {
			if j > len(tx.TxIn) {
				fmt.Fprintln(f, unspentOuts[j], unspentOutsLabel[j])
			}
		}
		if *verbose {
			fmt.Println(len(tx.TxIn), "spent output(s) removed from 'balance/unspent.txt'")
		}

		var addback int
		for out := range tx.TxOut {
			for j := range publ_addrs {
				if publ_addrs[j].Owns(tx.TxOut[out].Pk_script) {
					fmt.Fprintf(f, "%s-%03d # %.8f / %s\n", tx.Hash.String(), out,
						float64(tx.TxOut[out].Value)/1e8, publ_addrs[j].String())
					addback++
				}
			}
		}
		f.Close()

		if addback > 0 {
			f, _ = os.Create("balance/" + tx.Hash.String() + ".tx")
			if f != nil {
				f.Write(tx.Serialize())
				f.Close()
			}
			if *verbose {
				fmt.Println(addback, "new output(s) appended to 'balance/unspent.txt'")
			}
		}
	}
}
示例#10
0
文件: tx_test.go 项目: bityuan/gocoin
// Some tests from the satoshi's json files are not applicable
// ... for our architectre so lets just fake them.
func skip_broken_tests(tx *btc.Tx) bool {
	// No inputs
	if len(tx.TxIn) == 0 {
		return true
	}

	// Negative output
	for i := range tx.TxOut {
		if tx.TxOut[i].Value > btc.MAX_MONEY {
			return true
		}
	}

	// Duplicate inputs
	if len(tx.TxIn) > 1 {
		for i := 0; i < len(tx.TxIn)-1; i++ {
			for j := i + 1; j < len(tx.TxIn); j++ {
				if tx.TxIn[i].Input == tx.TxIn[j].Input {
					return true
				}
			}
		}
	}

	// Coinbase of w wrong size
	if tx.IsCoinBase() {
		if len(tx.TxIn[0].ScriptSig) < 2 {
			return true
		}
		if len(tx.TxIn[0].ScriptSig) > 100 {
			return true
		}
	}

	return false
}
示例#11
0
文件: signtx.go 项目: vancsj/gocoin
// prepare a signed transaction
func sign_tx(tx *btc.Tx) (all_signed bool) {
	all_signed = true
	for in := range tx.TxIn {
		uo := UO(unspentOuts[in])
		var found bool
		for j := range publ_addrs {
			if publ_addrs[j].Owns(uo.Pk_script) {
				er := tx.Sign(in, uo.Pk_script, btc.SIGHASH_ALL, publ_addrs[j].Pubkey, priv_keys[j][:])
				if er == nil {
					found = true
				} else {
					fmt.Println("Error signing input", in, "of", len(tx.TxIn))
					fmt.Println("...", er.Error())
				}
				break
			}
		}
		if !found {
			fmt.Println("WARNING: You do not have key for", hex.EncodeToString(uo.Pk_script))
			all_signed = false
		}
	}
	return
}
示例#12
0
func mk_out_tx(sig_scr, pk_scr []byte) (output_tx *btc.Tx) {
	// We build input_tx only to calculate it's hash for output_tx
	input_tx := new(btc.Tx)
	input_tx.Version = 1
	input_tx.TxIn = []*btc.TxIn{&btc.TxIn{Input: btc.TxPrevOut{Vout: 0xffffffff},
		ScriptSig: []byte{0, 0}, Sequence: 0xffffffff}}
	input_tx.TxOut = []*btc.TxOut{&btc.TxOut{Pk_script: pk_scr}}
	// Lock_time = 0

	output_tx = new(btc.Tx)
	output_tx.Version = 1
	output_tx.TxIn = []*btc.TxIn{&btc.TxIn{Input: btc.TxPrevOut{Hash: btc.Sha2Sum(input_tx.Serialize()), Vout: 0},
		ScriptSig: sig_scr, Sequence: 0xffffffff}}
	output_tx.TxOut = []*btc.TxOut{&btc.TxOut{}}
	// Lock_time = 0

	return
}
示例#13
0
文件: signtx.go 项目: piotrnar/gocoin
func write_tx_file(tx *btc.Tx) {
	var signedrawtx []byte
	if tx.SegWit != nil {
		signedrawtx = tx.SerializeNew()
	} else {
		signedrawtx = tx.Serialize()
	}
	tx.SetHash(signedrawtx)

	hs := tx.Hash.String()
	fmt.Println("TxID", hs)

	f, _ := os.Create(hs[:8] + ".txt")
	if f != nil {
		f.Write([]byte(hex.EncodeToString(signedrawtx)))
		f.Close()
		fmt.Println("Transaction data stored in", hs[:8]+".txt")
	}
}
示例#14
0
文件: signtx.go 项目: liudch/gocoin
// prepare a signed transaction
func sign_tx(tx *btc.Tx) (all_signed bool) {
	var multisig_done bool
	all_signed = true

	// go through each input
	for in := range tx.TxIn {
		if ms, _ := btc.NewMultiSigFromScript(tx.TxIn[in].ScriptSig); ms != nil {
			hash := tx.SignatureHash(ms.P2SH(), in, btc.SIGHASH_ALL)
			for ki := range ms.PublicKeys {
				k := public_to_key(ms.PublicKeys[ki])
				if k != nil {
					r, s, e := btc.EcdsaSign(k.Key, hash)
					if e != nil {
						println("ERROR in sign_tx:", e.Error())
						all_signed = false
					} else {
						btcsig := &btc.Signature{HashType: 0x01}
						btcsig.R.Set(r)
						btcsig.S.Set(s)

						ms.Signatures = append(ms.Signatures, btcsig)
						tx.TxIn[in].ScriptSig = ms.Bytes()
						multisig_done = true
					}
				}
			}
		} else {
			uo := getUO(&tx.TxIn[in].Input)
			if uo == nil {
				println("ERROR: Unkown input:", tx.TxIn[in].Input.String(), "- missing balance folder?")
				all_signed = false
				continue
			}
			adr := addr_from_pkscr(uo.Pk_script)
			if adr == nil {
				fmt.Println("WARNING: Don't know how to sign input number", in)
				fmt.Println(" Pk_script:", hex.EncodeToString(uo.Pk_script))
				all_signed = false
				continue
			}
			k := hash_to_key(adr.Hash160)
			if k == nil {
				fmt.Println("WARNING: You do not have key for", adr.String(), "at input", in)
				all_signed = false
				continue
			}
			er := tx.Sign(in, uo.Pk_script, btc.SIGHASH_ALL, k.BtcAddr.Pubkey, k.Key)
			if er != nil {
				fmt.Println("ERROR: Sign failed for input number", in, er.Error())
				all_signed = false
			}
		}
	}

	// reorder signatures if we signed any multisig inputs
	if multisig_done && !multisig_reorder(tx) {
		all_signed = false
	}

	if !all_signed {
		fmt.Println("WARNING: Not all the inputs have been signed")
	}

	return
}
示例#15
0
文件: signtx.go 项目: vancsj/gocoin
// 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)
		}
	}
}
示例#16
0
文件: signtx.go 项目: piotrnar/gocoin
// 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)
	}
}
示例#17
0
文件: sendtx.go 项目: liudch/gocoin
func dl_payment(w http.ResponseWriter, r *http.Request) {
	if !ipchecker(r) {
		return
	}

	var err string

	if len(r.Form["outcnt"]) == 1 {
		var thisbal chain.AllUnspentTx
		var pay_cmd string
		var totalinput, spentsofar uint64
		var change_addr *btc.BtcAddr
		var multisig_input []*wallet.MultisigAddr

		addrs_to_msign := make(map[string]bool)

		tx := new(btc.Tx)
		tx.Version = 1
		tx.Lock_time = 0

		outcnt, _ := strconv.ParseUint(r.Form["outcnt"][0], 10, 32)

		wallet.BalanceMutex.Lock()
		for i := 1; i <= int(outcnt); i++ {
			is := fmt.Sprint(i)
			if len(r.Form["txout"+is]) == 1 && r.Form["txout"+is][0] == "on" {
				hash := btc.NewUint256FromString(r.Form["txid"+is][0])
				if hash != nil {
					vout, er := strconv.ParseUint(r.Form["txvout"+is][0], 10, 32)
					if er == nil {
						var po = btc.TxPrevOut{Hash: hash.Hash, Vout: uint32(vout)}
						for j := range wallet.MyBalance {
							if wallet.MyBalance[j].TxPrevOut == po {
								thisbal = append(thisbal, wallet.MyBalance[j])

								// Add the input to our tx
								tin := new(btc.TxIn)
								tin.Input = wallet.MyBalance[j].TxPrevOut
								tin.Sequence = 0xffffffff
								tx.TxIn = append(tx.TxIn, tin)

								// Add new multisig address description
								_, msi := wallet.IsMultisig(wallet.MyBalance[j].BtcAddr)
								multisig_input = append(multisig_input, msi)
								if msi != nil {
									for ai := range msi.ListOfAddres {
										addrs_to_msign[msi.ListOfAddres[ai]] = true
									}
								}

								// Add the value to total input value
								totalinput += wallet.MyBalance[j].Value

								// If no change specified, use the first input addr as it
								if change_addr == nil {
									change_addr = wallet.MyBalance[j].BtcAddr
								}
							}
						}
					}
				}
			}
		}
		wallet.BalanceMutex.Unlock()

		for i := 1; ; i++ {
			adridx := fmt.Sprint("adr", i)
			btcidx := fmt.Sprint("btc", i)

			if len(r.Form[adridx]) != 1 || len(r.Form[btcidx]) != 1 {
				break
			}

			if len(r.Form[adridx][0]) > 1 {
				addr, er := btc.NewAddrFromString(r.Form[adridx][0])
				if er == nil {
					am, er := btc.StringToSatoshis(r.Form[btcidx][0])
					if er == nil && am > 0 {
						if pay_cmd == "" {
							pay_cmd = "wallet -useallinputs -send "
						} else {
							pay_cmd += ","
						}
						pay_cmd += addr.Enc58str + "=" + btc.UintToBtc(am)

						outs, er := btc.NewSpendOutputs(addr, am, common.CFG.Testnet)
						if er != nil {
							err = er.Error()
							goto error
						}
						tx.TxOut = append(tx.TxOut, outs...)

						spentsofar += am
					} else {
						err = "Incorrect amount (" + r.Form[btcidx][0] + ") for Output #" + fmt.Sprint(i)
						goto error
					}
				} else {
					err = "Incorrect address (" + r.Form[adridx][0] + ") for Output #" + fmt.Sprint(i)
					goto error
				}
			}
		}

		if pay_cmd == "" {
			err = "No inputs selected"
			goto error
		}

		am, er := btc.StringToSatoshis(r.Form["txfee"][0])
		if er != nil {
			err = "Incorrect fee value: " + r.Form["txfee"][0]
			goto error
		}

		pay_cmd += " -fee " + r.Form["txfee"][0]
		spentsofar += am

		if len(r.Form["change"][0]) > 1 {
			addr, er := btc.NewAddrFromString(r.Form["change"][0])
			if er != nil {
				err = "Incorrect change address: " + r.Form["change"][0]
				goto error
			}
			change_addr = addr
		}
		pay_cmd += " -change " + change_addr.String()

		if totalinput > spentsofar {
			// Add change output
			outs, er := btc.NewSpendOutputs(change_addr, totalinput-spentsofar, common.CFG.Testnet)
			if er != nil {
				err = er.Error()
				goto error
			}
			tx.TxOut = append(tx.TxOut, outs...)
		}

		buf := new(bytes.Buffer)
		zi := zip.NewWriter(buf)

		was_tx := make(map[[32]byte]bool, len(thisbal))
		for i := range thisbal {
			if was_tx[thisbal[i].TxPrevOut.Hash] {
				continue
			}
			was_tx[thisbal[i].TxPrevOut.Hash] = true
			txid := btc.NewUint256(thisbal[i].TxPrevOut.Hash[:])
			fz, _ := zi.Create("balance/" + txid.String() + ".tx")
			wallet.GetRawTransaction(thisbal[i].MinedAt, txid, fz)
		}

		fz, _ := zi.Create("balance/unspent.txt")
		for i := range thisbal {
			fmt.Fprintln(fz, thisbal[i].UnspentTextLine())
		}

		if len(addrs_to_msign) > 0 {
			// Multisig (or mixed) transaction ...
			for i := range multisig_input {
				if multisig_input[i] == nil {
					continue
				}
				d, er := hex.DecodeString(multisig_input[i].RedeemScript)
				if er != nil {
					println("ERROR parsing hex RedeemScript:", er.Error())
					continue
				}
				ms, er := btc.NewMultiSigFromP2SH(d)
				if er != nil {
					println("ERROR parsing bin RedeemScript:", er.Error())
					continue
				}
				tx.TxIn[i].ScriptSig = ms.Bytes()
			}
			fz, _ = zi.Create("multi_" + common.CFG.PayCommandName)
			fmt.Fprintln(fz, "wallet -raw tx2sign.txt")
			for k, _ := range addrs_to_msign {
				fmt.Fprintln(fz, "wallet -msign", k, "-raw ...")
			}
		} else {
			if pay_cmd != "" {
				fz, _ = zi.Create(common.CFG.PayCommandName)
				fz.Write([]byte(pay_cmd))
			}
		}

		// Non-multisig transaction ...
		fz, _ = zi.Create("tx2sign.txt")
		fz.Write([]byte(hex.EncodeToString(tx.Serialize())))

		zi.Close()
		w.Header()["Content-Type"] = []string{"application/zip"}
		w.Write(buf.Bytes())
		return
	} else {
		err = "Bad request"
	}
error:
	s := load_template("send_error.html")
	write_html_head(w, r)
	s = strings.Replace(s, "<!--ERROR_MSG-->", err, 1)
	w.Write([]byte(s))
	write_html_tail(w)
}
示例#18
0
文件: usif.go 项目: piotrnar/gocoin
func DecodeTxSops(tx *btc.Tx) (s string, missinginp bool, totinp, totout uint64, sigops uint, e error) {
	s += fmt.Sprintln("Transaction details (for your information):")
	s += fmt.Sprintln(len(tx.TxIn), "Input(s):")
	sigops = btc.WITNESS_SCALE_FACTOR * tx.GetLegacySigOpCount()
	for i := range tx.TxIn {
		s += fmt.Sprintf(" %3d %s", i, tx.TxIn[i].Input.String())
		var po *btc.TxOut

		inpid := btc.NewUint256(tx.TxIn[i].Input.Hash[:])
		if txinmem, ok := network.TransactionsToSend[inpid.BIdx()]; ok {
			s += fmt.Sprint(" mempool")
			if int(tx.TxIn[i].Input.Vout) >= len(txinmem.TxOut) {
				s += fmt.Sprintf(" - Vout TOO BIG (%d/%d)!", int(tx.TxIn[i].Input.Vout), len(txinmem.TxOut))
			} else {
				po = txinmem.TxOut[tx.TxIn[i].Input.Vout]
			}
		} else {
			po, _ = common.BlockChain.Unspent.UnspentGet(&tx.TxIn[i].Input)
			if po != nil {
				s += fmt.Sprintf("%8d", po.BlockHeight)
			}
		}
		if po != nil {
			ok := script.VerifyTxScript(po.Pk_script, po.Value, i, tx, script.VER_P2SH|script.VER_DERSIG|script.VER_CLTV)
			if !ok {
				s += fmt.Sprintln("\nERROR: The transacion does not have a valid signature.")
				e = errors.New("Invalid signature")
				return
			}
			totinp += po.Value

			ads := "???"
			if ad := btc.NewAddrFromPkScript(po.Pk_script, common.Testnet); ad != nil {
				ads = ad.String()
			}
			s += fmt.Sprintf(" %15.8f BTC @ %s", float64(po.Value)/1e8, ads)

			if btc.IsP2SH(po.Pk_script) {
				so := btc.WITNESS_SCALE_FACTOR * btc.GetP2SHSigOpCount(tx.TxIn[i].ScriptSig)
				s += fmt.Sprintf("  + %d sigops", so)
				sigops += so
			}

			swo := tx.CountWitnessSigOps(i, po.Pk_script)
			if swo > 0 {
				s += fmt.Sprintf("  + %d segops", swo)
				sigops += swo
			}

			s += "\n"
		} else {
			s += fmt.Sprintln(" - UNKNOWN INPUT")
			missinginp = true
		}
	}
	s += fmt.Sprintln(len(tx.TxOut), "Output(s):")
	for i := range tx.TxOut {
		totout += tx.TxOut[i].Value
		adr := btc.NewAddrFromPkScript(tx.TxOut[i].Pk_script, common.Testnet)
		if adr != nil {
			s += fmt.Sprintf(" %15.8f BTC to adr %s\n", float64(tx.TxOut[i].Value)/1e8, adr.String())
		} else {
			s += fmt.Sprintf(" %15.8f BTC to scr %s\n", float64(tx.TxOut[i].Value)/1e8, hex.EncodeToString(tx.TxOut[i].Pk_script))
		}
	}
	if missinginp {
		s += fmt.Sprintln("WARNING: There are missing inputs and we cannot calc input BTC amount.")
		s += fmt.Sprintln("If there is somethign wrong with this transaction, you can loose money...")
	} else {
		s += fmt.Sprintf("All OK: %.8f BTC in -> %.8f BTC out, with %.8f BTC fee\n", float64(totinp)/1e8,
			float64(totout)/1e8, float64(totinp-totout)/1e8)
	}

	s += fmt.Sprintln("ECDSA sig operations : ", sigops)

	return
}
示例#19
0
文件: txs.go 项目: piotrnar/gocoin
func output_tx_xml(w http.ResponseWriter, tx *btc.Tx) {
	w.Write([]byte("<input_list>"))
	for i := range tx.TxIn {
		w.Write([]byte("<input>"))
		w.Write([]byte("<script_sig>"))
		w.Write([]byte(hex.EncodeToString(tx.TxIn[i].ScriptSig)))
		w.Write([]byte("</script_sig>"))
		var po *btc.TxOut
		inpid := btc.NewUint256(tx.TxIn[i].Input.Hash[:])
		if txinmem, ok := network.TransactionsToSend[inpid.BIdx()]; ok {
			if int(tx.TxIn[i].Input.Vout) < len(txinmem.TxOut) {
				po = txinmem.TxOut[tx.TxIn[i].Input.Vout]
			}
		} else {
			po, _ = common.BlockChain.Unspent.UnspentGet(&tx.TxIn[i].Input)
		}
		if po != nil {
			ok := script.VerifyTxScript(po.Pk_script, po.Value, i, tx, script.STANDARD_VERIFY_FLAGS)
			if !ok {
				w.Write([]byte("<status>Script FAILED</status>"))
			} else {
				w.Write([]byte("<status>OK</status>"))
			}
			fmt.Fprint(w, "<value>", po.Value, "</value>")
			fmt.Fprint(w, "<pkscript>", hex.EncodeToString(po.Pk_script), "</pkscript>")
			if ad := btc.NewAddrFromPkScript(po.Pk_script, common.Testnet); ad != nil {
				fmt.Fprint(w, "<addr>", ad.String(), "</addr>")
			}
			fmt.Fprint(w, "<block>", po.BlockHeight, "</block>")

			if btc.IsP2SH(po.Pk_script) {
				fmt.Fprint(w, "<input_sigops>", btc.WITNESS_SCALE_FACTOR*btc.GetP2SHSigOpCount(tx.TxIn[i].ScriptSig), "</input_sigops>")
			}
			fmt.Fprint(w, "<witness_sigops>", tx.CountWitnessSigOps(i, po.Pk_script), "</witness_sigops>")
		} else {
			w.Write([]byte("<status>UNKNOWN INPUT</status>"))
		}
		fmt.Fprint(w, "<sequence>", tx.TxIn[i].Sequence, "</sequence>")

		if tx.SegWit != nil {
			w.Write([]byte("<segwit>"))
			for _, wit := range tx.SegWit[i] {
				w.Write([]byte("<witness>"))
				w.Write([]byte(hex.EncodeToString(wit)))
				w.Write([]byte("</witness>"))
			}
			w.Write([]byte("</segwit>"))
		}
		w.Write([]byte("</input>"))
	}
	w.Write([]byte("</input_list>"))

	w.Write([]byte("<output_list>"))
	for i := range tx.TxOut {
		w.Write([]byte("<output>"))
		fmt.Fprint(w, "<value>", tx.TxOut[i].Value, "</value>")
		adr := btc.NewAddrFromPkScript(tx.TxOut[i].Pk_script, common.Testnet)
		if adr != nil {
			fmt.Fprint(w, "<addr>", adr.String(), "</addr>")
		} else {
			fmt.Fprint(w, "<addr>", "scr:"+hex.EncodeToString(tx.TxOut[i].Pk_script), "</addr>")
		}
		w.Write([]byte("</output>"))
	}
	w.Write([]byte("</output_list>"))
}
示例#20
0
文件: script.go 项目: liudch/gocoin
func evalScript(p []byte, stack *scrStack, tx *btc.Tx, inp int, ver_flags uint32) bool {
	if DBG_SCR {
		fmt.Println("script len", len(p))
	}

	if len(p) > 10000 {
		if DBG_ERR {
			fmt.Println("script too long", len(p))
		}
		return false
	}

	defer func() {
		if r := recover(); r != nil {
			if DBG_ERR {
				err, ok := r.(error)
				if !ok {
					err = fmt.Errorf("pkg: %v", r)
				}
				fmt.Println("evalScript panic:", err.Error())
				fmt.Println(string(debug.Stack()))
			}
		}
	}()

	var exestack scrStack
	var altstack scrStack
	sta, idx, opcnt := 0, 0, 0
	checkMinVals := (ver_flags & VER_MINDATA) != 0
	for idx < len(p) {
		inexec := exestack.nofalse()

		// Read instruction
		opcode, pushval, n, e := btc.GetOpcode(p[idx:])
		if e != nil {
			//fmt.Println(e.Error())
			//fmt.Println("A", idx, hex.EncodeToString(p))
			return false
		}
		idx += n

		if DBG_SCR {
			fmt.Printf("\nExecuting opcode 0x%02x  n=%d  inexec:%t  push:%s..\n",
				opcode, n, inexec, hex.EncodeToString(pushval))
			stack.print()
		}

		if pushval != nil && len(pushval) > btc.MAX_SCRIPT_ELEMENT_SIZE {
			if DBG_ERR {
				fmt.Println("pushval too long", len(pushval))
			}
			return false
		}

		if opcode > 0x60 {
			opcnt++
			if opcnt > 201 {
				if DBG_ERR {
					fmt.Println("evalScript: too many opcodes A")
				}
				return false
			}
		}

		if opcode == 0x7e /*OP_CAT*/ ||
			opcode == 0x7f /*OP_SUBSTR*/ ||
			opcode == 0x80 /*OP_LEFT*/ ||
			opcode == 0x81 /*OP_RIGHT*/ ||
			opcode == 0x83 /*OP_INVERT*/ ||
			opcode == 0x84 /*OP_AND*/ ||
			opcode == 0x85 /*OP_OR*/ ||
			opcode == 0x86 /*OP_XOR*/ ||
			opcode == 0x8d /*OP_2MUL*/ ||
			opcode == 0x8e /*OP_2DIV*/ ||
			opcode == 0x95 /*OP_MUL*/ ||
			opcode == 0x96 /*OP_DIV*/ ||
			opcode == 0x97 /*OP_MOD*/ ||
			opcode == 0x98 /*OP_LSHIFT*/ ||
			opcode == 0x99 /*OP_RSHIFT*/ {
			if DBG_ERR {
				fmt.Println("Unsupported opcode", opcode)
			}
			return false
		}

		if inexec && 0 <= opcode && opcode <= btc.OP_PUSHDATA4 {
			if checkMinVals && !checkMinimalPush(pushval, opcode) {
				if DBG_ERR {
					fmt.Println("Push value not in a minimal format", hex.EncodeToString(pushval))
				}
				return false
			}
			stack.push(pushval)
			if DBG_SCR {
				fmt.Println("pushed", len(pushval), "bytes")
			}
		} else if inexec || (0x63 /*OP_IF*/ <= opcode && opcode <= 0x68 /*OP_ENDIF*/) {
			switch {
			case opcode == 0x4f: // OP_1NEGATE
				stack.pushInt(-1)

			case opcode >= 0x51 && opcode <= 0x60: // OP_1-OP_16
				stack.pushInt(int64(opcode - 0x50))

			case opcode == 0x61: // OP_NOP
				// Do nothing

			/* - not handled
			OP_VER = 0x62
			*/

			case opcode == 0x63 || opcode == 0x64: //OP_IF || OP_NOTIF
				// <expression> if [statements] [else [statements]] endif
				val := false
				if inexec {
					if stack.size() < 1 {
						if DBG_ERR {
							fmt.Println("Stack too short for", opcode)
						}
						return false
					}
					if opcode == 0x63 /*OP_IF*/ {
						val = stack.popBool()
					} else {
						val = !stack.popBool()
					}
				}
				if DBG_SCR {
					fmt.Println(inexec, "if pushing", val, "...")
				}
				exestack.pushBool(val)

			/* - not handled
			   OP_VERIF = 0x65,
			   OP_VERNOTIF = 0x66,
			*/
			case opcode == 0x67: //OP_ELSE
				if exestack.size() == 0 {
					if DBG_ERR {
						fmt.Println("exestack empty in OP_ELSE")
					}
				}
				exestack.pushBool(!exestack.popBool())

			case opcode == 0x68: //OP_ENDIF
				if exestack.size() == 0 {
					if DBG_ERR {
						fmt.Println("exestack empty in OP_ENDIF")
					}
				}
				exestack.pop()

			case opcode == 0x69: //OP_VERIFY
				if stack.size() < 1 {
					if DBG_ERR {
						fmt.Println("Stack too short for opcode", opcode)
					}
					return false
				}
				if !stack.topBool(-1) {
					return false
				}
				stack.pop()

			case opcode == 0x6b: //OP_TOALTSTACK
				if stack.size() < 1 {
					if DBG_ERR {
						fmt.Println("Stack too short for opcode", opcode)
					}
					return false
				}
				altstack.push(stack.pop())

			case opcode == 0x6c: //OP_FROMALTSTACK
				if altstack.size() < 1 {
					if DBG_ERR {
						fmt.Println("AltStack too short for opcode", opcode)
					}
					return false
				}
				stack.push(altstack.pop())

			case opcode == 0x6d: //OP_2DROP
				if stack.size() < 2 {
					if DBG_ERR {
						fmt.Println("Stack too short for opcode", opcode)
					}
					return false
				}
				stack.pop()
				stack.pop()

			case opcode == 0x6e: //OP_2DUP
				if stack.size() < 2 {
					if DBG_ERR {
						fmt.Println("Stack too short for opcode", opcode)
					}
					return false
				}
				x1 := stack.top(-1)
				x2 := stack.top(-2)
				stack.push(x2)
				stack.push(x1)

			case opcode == 0x6f: //OP_3DUP
				if stack.size() < 3 {
					if DBG_ERR {
						fmt.Println("Stack too short for opcode", opcode)
					}
					return false
				}
				x1 := stack.top(-3)
				x2 := stack.top(-2)
				x3 := stack.top(-1)
				stack.push(x1)
				stack.push(x2)
				stack.push(x3)

			case opcode == 0x70: //OP_2OVER
				if stack.size() < 4 {
					if DBG_ERR {
						fmt.Println("Stack too short for opcode", opcode)
					}
					return false
				}
				x1 := stack.top(-4)
				x2 := stack.top(-3)
				stack.push(x1)
				stack.push(x2)

			case opcode == 0x71: //OP_2ROT
				// (x1 x2 x3 x4 x5 x6 -- x3 x4 x5 x6 x1 x2)
				if stack.size() < 6 {
					if DBG_ERR {
						fmt.Println("Stack too short for opcode", opcode)
					}
					return false
				}
				x6 := stack.pop()
				x5 := stack.pop()
				x4 := stack.pop()
				x3 := stack.pop()
				x2 := stack.pop()
				x1 := stack.pop()
				stack.push(x3)
				stack.push(x4)
				stack.push(x5)
				stack.push(x6)
				stack.push(x1)
				stack.push(x2)

			case opcode == 0x72: //OP_2SWAP
				// (x1 x2 x3 x4 -- x3 x4 x1 x2)
				if stack.size() < 4 {
					if DBG_ERR {
						fmt.Println("Stack too short for opcode", opcode)
					}
					return false
				}
				x4 := stack.pop()
				x3 := stack.pop()
				x2 := stack.pop()
				x1 := stack.pop()
				stack.push(x3)
				stack.push(x4)
				stack.push(x1)
				stack.push(x2)

			case opcode == 0x73: //OP_IFDUP
				if stack.size() < 1 {
					if DBG_ERR {
						fmt.Println("Stack too short for opcode", opcode)
					}
					return false
				}
				if stack.topBool(-1) {
					stack.push(stack.top(-1))
				}

			case opcode == 0x74: //OP_DEPTH
				stack.pushInt(int64(stack.size()))

			case opcode == 0x75: //OP_DROP
				if stack.size() < 1 {
					if DBG_ERR {
						fmt.Println("Stack too short for opcode", opcode)
					}
					return false
				}
				stack.pop()

			case opcode == 0x76: //OP_DUP
				if stack.size() < 1 {
					if DBG_ERR {
						fmt.Println("Stack too short for opcode", opcode)
					}
					return false
				}
				el := stack.pop()
				stack.push(el)
				stack.push(el)

			case opcode == 0x77: //OP_NIP
				if stack.size() < 2 {
					if DBG_ERR {
						fmt.Println("Stack too short for opcode", opcode)
					}
					return false
				}
				x := stack.pop()
				stack.pop()
				stack.push(x)

			case opcode == 0x78: //OP_OVER
				if stack.size() < 2 {
					if DBG_ERR {
						fmt.Println("Stack too short for opcode", opcode)
					}
					return false
				}
				stack.push(stack.top(-2))

			case opcode == 0x79 || opcode == 0x7a: //OP_PICK || OP_ROLL
				if stack.size() < 2 {
					if DBG_ERR {
						fmt.Println("Stack too short for opcode", opcode)
					}
					return false
				}
				n := stack.popInt(checkMinVals)
				if n < 0 || n >= int64(stack.size()) {
					if DBG_ERR {
						fmt.Println("Wrong n for opcode", opcode)
					}
					return false
				}
				if opcode == 0x79 /*OP_PICK*/ {
					stack.push(stack.top(int(-1 - n)))
				} else if n > 0 {
					tmp := make([][]byte, n)
					for i := range tmp {
						tmp[i] = stack.pop()
					}
					xn := stack.pop()
					for i := len(tmp) - 1; i >= 0; i-- {
						stack.push(tmp[i])
					}
					stack.push(xn)
				}

			case opcode == 0x7b: //OP_ROT
				if stack.size() < 3 {
					if DBG_ERR {
						fmt.Println("Stack too short for opcode", opcode)
					}
					return false
				}
				x3 := stack.pop()
				x2 := stack.pop()
				x1 := stack.pop()
				stack.push(x2)
				stack.push(x3)
				stack.push(x1)

			case opcode == 0x7c: //OP_SWAP
				if stack.size() < 2 {
					if DBG_ERR {
						fmt.Println("Stack too short for opcode", opcode)
					}
					return false
				}
				x1 := stack.pop()
				x2 := stack.pop()
				stack.push(x1)
				stack.push(x2)

			case opcode == 0x7d: //OP_TUCK
				if stack.size() < 2 {
					if DBG_ERR {
						fmt.Println("Stack too short for opcode", opcode)
					}
					return false
				}
				x1 := stack.pop()
				x2 := stack.pop()
				stack.push(x1)
				stack.push(x2)
				stack.push(x1)

			case opcode == 0x82: //OP_SIZE
				if stack.size() < 1 {
					if DBG_ERR {
						fmt.Println("Stack too short for opcode", opcode)
					}
					return false
				}
				stack.pushInt(int64(len(stack.top(-1))))

			case opcode == 0x87 || opcode == 0x88: //OP_EQUAL || OP_EQUALVERIFY
				if stack.size() < 2 {
					if DBG_ERR {
						fmt.Println("Stack too short for opcode", opcode)
					}
					return false
				}
				a := stack.pop()
				b := stack.pop()
				if opcode == 0x88 { //OP_EQUALVERIFY
					if !bytes.Equal(a, b) {
						return false
					}
				} else {
					stack.pushBool(bytes.Equal(a, b))
				}

			/* - not handled
			OP_RESERVED1 = 0x89,
			OP_RESERVED2 = 0x8a,
			*/

			case opcode == 0x8b: //OP_1ADD
				if stack.size() < 1 {
					if DBG_ERR {
						fmt.Println("Stack too short for opcode", opcode)
					}
					return false
				}
				stack.pushInt(stack.popInt(checkMinVals) + 1)

			case opcode == 0x8c: //OP_1SUB
				if stack.size() < 1 {
					if DBG_ERR {
						fmt.Println("Stack too short for opcode", opcode)
					}
					return false
				}
				stack.pushInt(stack.popInt(checkMinVals) - 1)

			case opcode == 0x8f: //OP_NEGATE
				if stack.size() < 1 {
					if DBG_ERR {
						fmt.Println("Stack too short for opcode", opcode)
					}
					return false
				}
				stack.pushInt(-stack.popInt(checkMinVals))

			case opcode == 0x90: //OP_ABS
				if stack.size() < 1 {
					if DBG_ERR {
						fmt.Println("Stack too short for opcode", opcode)
					}
					return false
				}
				a := stack.popInt(checkMinVals)
				if a < 0 {
					stack.pushInt(-a)
				} else {
					stack.pushInt(a)
				}

			case opcode == 0x91: //OP_NOT
				if stack.size() < 1 {
					if DBG_ERR {
						fmt.Println("Stack too short for opcode", opcode)
					}
					return false
				}
				stack.pushBool(stack.popInt(checkMinVals) == 0)

			case opcode == 0x92: //OP_0NOTEQUAL
				if stack.size() < 1 {
					if DBG_ERR {
						fmt.Println("Stack too short for opcode", opcode)
					}
					return false
				}
				d := stack.pop()
				if checkMinVals && len(d) > 1 {
					if DBG_ERR {
						fmt.Println("Not minimal bool value", hex.EncodeToString(d))
					}
					return false
				}
				stack.pushBool(bts2bool(d))

			case opcode == 0x93 || //OP_ADD
				opcode == 0x94 || //OP_SUB
				opcode == 0x9a || //OP_BOOLAND
				opcode == 0x9b || //OP_BOOLOR
				opcode == 0x9c || opcode == 0x9d || //OP_NUMEQUAL || OP_NUMEQUALVERIFY
				opcode == 0x9e || //OP_NUMNOTEQUAL
				opcode == 0x9f || //OP_LESSTHAN
				opcode == 0xa0 || //OP_GREATERTHAN
				opcode == 0xa1 || //OP_LESSTHANOREQUAL
				opcode == 0xa2 || //OP_GREATERTHANOREQUAL
				opcode == 0xa3 || //OP_MIN
				opcode == 0xa4: //OP_MAX
				if stack.size() < 2 {
					if DBG_ERR {
						fmt.Println("Stack too short for opcode", opcode)
					}
					return false
				}
				bn2 := stack.popInt(checkMinVals)
				bn1 := stack.popInt(checkMinVals)
				var bn int64
				switch opcode {
				case 0x93:
					bn = bn1 + bn2 // OP_ADD
				case 0x94:
					bn = bn1 - bn2 // OP_SUB
				case 0x9a:
					bn = b2i(bn1 != 0 && bn2 != 0) // OP_BOOLAND
				case 0x9b:
					bn = b2i(bn1 != 0 || bn2 != 0) // OP_BOOLOR
				case 0x9c:
					bn = b2i(bn1 == bn2) // OP_NUMEQUAL
				case 0x9d:
					bn = b2i(bn1 == bn2) // OP_NUMEQUALVERIFY
				case 0x9e:
					bn = b2i(bn1 != bn2) // OP_NUMNOTEQUAL
				case 0x9f:
					bn = b2i(bn1 < bn2) // OP_LESSTHAN
				case 0xa0:
					bn = b2i(bn1 > bn2) // OP_GREATERTHAN
				case 0xa1:
					bn = b2i(bn1 <= bn2) // OP_LESSTHANOREQUAL
				case 0xa2:
					bn = b2i(bn1 >= bn2) // OP_GREATERTHANOREQUAL
				case 0xa3: // OP_MIN
					if bn1 < bn2 {
						bn = bn1
					} else {
						bn = bn2
					}
				case 0xa4: // OP_MAX
					if bn1 > bn2 {
						bn = bn1
					} else {
						bn = bn2
					}
				default:
					panic("invalid opcode")
				}
				if opcode == 0x9d { //OP_NUMEQUALVERIFY
					if bn == 0 {
						return false
					}
				} else {
					stack.pushInt(bn)
				}

			case opcode == 0xa5: //OP_WITHIN
				if stack.size() < 3 {
					if DBG_ERR {
						fmt.Println("Stack too short for opcode", opcode)
					}
					return false
				}
				bn3 := stack.popInt(checkMinVals)
				bn2 := stack.popInt(checkMinVals)
				bn1 := stack.popInt(checkMinVals)
				stack.pushBool(bn2 <= bn1 && bn1 < bn3)

			case opcode == 0xa6: //OP_RIPEMD160
				if stack.size() < 1 {
					if DBG_ERR {
						fmt.Println("Stack too short for opcode", opcode)
					}
					return false
				}
				rim := ripemd160.New()
				rim.Write(stack.pop()[:])
				stack.push(rim.Sum(nil)[:])

			case opcode == 0xa7: //OP_SHA1
				if stack.size() < 1 {
					if DBG_ERR {
						fmt.Println("Stack too short for opcode", opcode)
					}
					return false
				}
				sha := sha1.New()
				sha.Write(stack.pop()[:])
				stack.push(sha.Sum(nil)[:])

			case opcode == 0xa8: //OP_SHA256
				if stack.size() < 1 {
					if DBG_ERR {
						fmt.Println("Stack too short for opcode", opcode)
					}
					return false
				}
				sha := sha256.New()
				sha.Write(stack.pop()[:])
				stack.push(sha.Sum(nil)[:])

			case opcode == 0xa9: //OP_HASH160
				if stack.size() < 1 {
					if DBG_ERR {
						fmt.Println("Stack too short for opcode", opcode)
					}
					return false
				}
				rim160 := btc.Rimp160AfterSha256(stack.pop())
				stack.push(rim160[:])

			case opcode == 0xaa: //OP_HASH256
				if stack.size() < 1 {
					if DBG_ERR {
						fmt.Println("Stack too short for opcode", opcode)
					}
					return false
				}
				h := btc.Sha2Sum(stack.pop())
				stack.push(h[:])

			case opcode == 0xab: // OP_CODESEPARATOR
				sta = idx

			case opcode == 0xac || opcode == 0xad: // OP_CHECKSIG || OP_CHECKSIGVERIFY

				if stack.size() < 2 {
					if DBG_ERR {
						fmt.Println("Stack too short for opcode", opcode)
					}
					return false
				}
				var ok bool
				pk := stack.pop()
				si := stack.pop()

				// BIP-0066
				if !CheckSignatureEncoding(si, ver_flags) {
					if DBG_ERR {
						fmt.Println("Invalid Signature Encoding A")
					}
					return false
				}

				if len(si) > 0 {
					sh := tx.SignatureHash(delSig(p[sta:], si), inp, int32(si[len(si)-1]))
					ok = btc.EcdsaVerify(pk, si, sh)
				}
				if !ok && DBG_ERR {
					if DBG_ERR {
						fmt.Println("EcdsaVerify fail 1")
					}
				}

				if DBG_SCR {
					fmt.Println("ver:", ok)
				}
				if opcode == 0xad {
					if !ok { // OP_CHECKSIGVERIFY
						return false
					}
				} else { // OP_CHECKSIG
					stack.pushBool(ok)
				}

			case opcode == 0xae || opcode == 0xaf: //OP_CHECKMULTISIG || OP_CHECKMULTISIGVERIFY
				//fmt.Println("OP_CHECKMULTISIG ...")
				//stack.print()
				if stack.size() < 1 {
					if DBG_ERR {
						fmt.Println("OP_CHECKMULTISIG: Stack too short A")
					}
					return false
				}
				i := 1
				keyscnt := stack.topInt(-i, checkMinVals)
				if keyscnt < 0 || keyscnt > 20 {
					fmt.Println("OP_CHECKMULTISIG: Wrong number of keys")
					return false
				}
				opcnt += int(keyscnt)
				if opcnt > 201 {
					if DBG_ERR {
						fmt.Println("evalScript: too many opcodes B")
					}
					return false
				}
				i++
				ikey := i
				i += int(keyscnt)
				if stack.size() < i {
					if DBG_ERR {
						fmt.Println("OP_CHECKMULTISIG: Stack too short B")
					}
					return false
				}
				sigscnt := stack.topInt(-i, checkMinVals)
				if sigscnt < 0 || sigscnt > keyscnt {
					fmt.Println("OP_CHECKMULTISIG: sigscnt error")
					return false
				}
				i++
				isig := i
				i += int(sigscnt)
				if stack.size() < i {
					if DBG_ERR {
						fmt.Println("OP_CHECKMULTISIG: Stack too short C")
					}
					return false
				}

				xxx := p[sta:]
				for k := 0; k < int(sigscnt); k++ {
					xxx = delSig(xxx, stack.top(-isig-k))
				}

				success := true
				for sigscnt > 0 {
					pk := stack.top(-ikey)
					si := stack.top(-isig)

					// BIP-0066
					if !CheckSignatureEncoding(si, ver_flags) {
						if DBG_ERR {
							fmt.Println("Invalid Signature Encoding B")
						}
						return false
					}

					if len(si) > 0 {
						sh := tx.SignatureHash(xxx, inp, int32(si[len(si)-1]))
						if btc.EcdsaVerify(pk, si, sh) {
							isig++
							sigscnt--
						}
					}

					ikey++
					keyscnt--

					// If there are more signatures left than keys left,
					// then too many signatures have failed
					if sigscnt > keyscnt {
						success = false
						break
					}
				}
				for i > 0 {
					i--
					stack.pop()
				}
				if opcode == 0xaf {
					if !success { // OP_CHECKMULTISIGVERIFY
						return false
					}
				} else {
					stack.pushBool(success)
				}

			case opcode >= 0xb1: //OP_NOP2 or OP_CHECKLOCKTIMEVERIFY
				if DBG_SCR {
					println("OP_NOP2...")
				}

				if (ver_flags & VER_CLTV) == 0 {
					break // Just do NOP2
				}

				if DBG_SCR {
					println("OP_CHECKLOCKTIMEVERIFY...")
				}

				if stack.size() < 1 {
					if DBG_ERR {
						fmt.Println("OP_CHECKLOCKTIMEVERIFY: Stack too short")
					}
					return false
				}

				d := stack.top(-1)
				if len(d) > 5 {
					if DBG_ERR {
						fmt.Println("OP_CHECKLOCKTIMEVERIFY: locktime field too long", len(d))
					}
					return false
				}

				if DBG_SCR {
					fmt.Println("val from stack", hex.EncodeToString(d))
				}

				locktime := bts2int_ext(d, 5, checkMinVals)
				if locktime < 0 {
					if DBG_ERR {
						fmt.Println("OP_CHECKLOCKTIMEVERIFY: negative locktime")
					}
					return false
				}

				if !((tx.Lock_time < LOCKTIME_THRESHOLD && locktime < LOCKTIME_THRESHOLD) ||
					(tx.Lock_time >= LOCKTIME_THRESHOLD && locktime >= LOCKTIME_THRESHOLD)) {
					if DBG_ERR {
						fmt.Println("OP_CHECKLOCKTIMEVERIFY: broken lock value")
					}
					return false
				}

				if DBG_SCR {
					println("locktime > int64(tx.Lock_time)", locktime, int64(tx.Lock_time))
					println(" ... seq", len(tx.TxIn), inp, tx.TxIn[inp].Sequence)
				}

				// Actually compare the specified lock time with the transaction.
				if locktime > int64(tx.Lock_time) {
					if DBG_ERR {
						fmt.Println("OP_CHECKLOCKTIMEVERIFY: Locktime requirement not satisfied")
					}
					return false
				}

				if tx.TxIn[inp].Sequence == 0xffffffff {
					if DBG_ERR {
						fmt.Println("OP_CHECKLOCKTIMEVERIFY: TxIn final")
					}
					return false
				}

				// OP_CHECKLOCKTIMEVERIFY passed successfully

			case opcode >= 0xb0 || opcode >= 0xb2 && opcode <= 0xb9: //OP_NOP1 || OP_NOP3..OP_NOP10
				// just do nothing

			default:
				if DBG_ERR {
					fmt.Printf("Unhandled opcode 0x%02x - a handler must be implemented\n", opcode)
					stack.print()
					fmt.Println("Rest of the script:", hex.EncodeToString(p[idx:]))
				}
				return false
			}
		}

		if DBG_SCR {
			fmt.Printf("Finished Executing opcode 0x%02x\n", opcode)
			stack.print()
		}
		if stack.size()+altstack.size() > 1000 {
			if DBG_ERR {
				fmt.Println("Stack too big")
			}
			return false
		}
	}

	if DBG_SCR {
		fmt.Println("END OF SCRIPT")
		stack.print()
	}

	if exestack.size() > 0 {
		if DBG_ERR {
			fmt.Println("Unfinished if..")
		}
		return false
	}

	return true
}
示例#21
0
文件: sendtx.go 项目: piotrnar/gocoin
func dl_payment(w http.ResponseWriter, r *http.Request) {
	if !ipchecker(r) {
		return
	}

	var err string

	if len(r.Form["outcnt"]) == 1 {
		var thisbal chain.AllUnspentTx
		var pay_cmd string
		var totalinput, spentsofar uint64
		var change_addr *btc.BtcAddr

		tx := new(btc.Tx)
		tx.Version = 1
		tx.Lock_time = 0

		seq, er := strconv.ParseInt(r.Form["tx_seq"][0], 10, 64)
		if er != nil || seq < -2 || seq > 0xffffffff {
			err = "Incorrect Sequence value: " + r.Form["tx_seq"][0]
			goto error
		}

		outcnt, _ := strconv.ParseUint(r.Form["outcnt"][0], 10, 32)

		lck := new(usif.OneLock)
		lck.In.Add(1)
		lck.Out.Add(1)
		usif.LocksChan <- lck
		lck.In.Wait()
		defer lck.Out.Done()

		for i := 1; i <= int(outcnt); i++ {
			is := fmt.Sprint(i)
			if len(r.Form["txout"+is]) == 1 && r.Form["txout"+is][0] == "on" {
				hash := btc.NewUint256FromString(r.Form["txid"+is][0])
				if hash != nil {
					vout, er := strconv.ParseUint(r.Form["txvout"+is][0], 10, 32)
					if er == nil {
						var po = btc.TxPrevOut{Hash: hash.Hash, Vout: uint32(vout)}
						if res, er := common.BlockChain.Unspent.UnspentGet(&po); er == nil {
							addr := btc.NewAddrFromPkScript(res.Pk_script, common.Testnet)

							unsp := &chain.OneUnspentTx{TxPrevOut: po, Value: res.Value,
								MinedAt: res.BlockHeight, Coinbase: res.WasCoinbase, BtcAddr: addr}

							thisbal = append(thisbal, unsp)

							// Add the input to our tx
							tin := new(btc.TxIn)
							tin.Input = po
							tin.Sequence = uint32(seq)
							tx.TxIn = append(tx.TxIn, tin)

							// Add the value to total input value
							totalinput += res.Value

							// If no change specified, use the first input addr as it
							if change_addr == nil {
								change_addr = addr
							}
						}
					}
				}
			}
		}

		if change_addr == nil {
			// There werte no inputs
			return
		}
		//wallet.BalanceMutex.Lock()
		//wallet.BalanceMutex.Unlock()

		for i := 1; ; i++ {
			adridx := fmt.Sprint("adr", i)
			btcidx := fmt.Sprint("btc", i)

			if len(r.Form[adridx]) != 1 || len(r.Form[btcidx]) != 1 {
				break
			}

			if len(r.Form[adridx][0]) > 1 {
				addr, er := btc.NewAddrFromString(r.Form[adridx][0])
				if er == nil {
					am, er := btc.StringToSatoshis(r.Form[btcidx][0])
					if er == nil && am > 0 {
						if pay_cmd == "" {
							pay_cmd = "wallet -useallinputs -send "
						} else {
							pay_cmd += ","
						}
						pay_cmd += addr.Enc58str + "=" + btc.UintToBtc(am)

						outs, er := btc.NewSpendOutputs(addr, am, common.CFG.Testnet)
						if er != nil {
							err = er.Error()
							goto error
						}
						tx.TxOut = append(tx.TxOut, outs...)

						spentsofar += am
					} else {
						err = "Incorrect amount (" + r.Form[btcidx][0] + ") for Output #" + fmt.Sprint(i)
						goto error
					}
				} else {
					err = "Incorrect address (" + r.Form[adridx][0] + ") for Output #" + fmt.Sprint(i)
					goto error
				}
			}
		}

		if pay_cmd == "" {
			err = "No inputs selected"
			goto error
		}

		pay_cmd += fmt.Sprint(" -seq ", seq)

		am, er := btc.StringToSatoshis(r.Form["txfee"][0])
		if er != nil {
			err = "Incorrect fee value: " + r.Form["txfee"][0]
			goto error
		}

		pay_cmd += " -fee " + r.Form["txfee"][0]
		spentsofar += am

		if len(r.Form["change"][0]) > 1 {
			addr, er := btc.NewAddrFromString(r.Form["change"][0])
			if er != nil {
				err = "Incorrect change address: " + r.Form["change"][0]
				goto error
			}
			change_addr = addr
		}
		pay_cmd += " -change " + change_addr.String()

		if totalinput > spentsofar {
			// Add change output
			outs, er := btc.NewSpendOutputs(change_addr, totalinput-spentsofar, common.CFG.Testnet)
			if er != nil {
				err = er.Error()
				goto error
			}
			tx.TxOut = append(tx.TxOut, outs...)
		}

		buf := new(bytes.Buffer)
		zi := zip.NewWriter(buf)

		was_tx := make(map[[32]byte]bool, len(thisbal))
		for i := range thisbal {
			if was_tx[thisbal[i].TxPrevOut.Hash] {
				continue
			}
			was_tx[thisbal[i].TxPrevOut.Hash] = true
			txid := btc.NewUint256(thisbal[i].TxPrevOut.Hash[:])
			fz, _ := zi.Create("balance/" + txid.String() + ".tx")
			if dat, er := common.BlockChain.GetRawTx(thisbal[i].MinedAt, txid); er == nil {
				fz.Write(dat)
			} else {
				println(er.Error())
			}
		}

		fz, _ := zi.Create("balance/unspent.txt")
		for i := range thisbal {
			fmt.Fprintln(fz, thisbal[i].UnspentTextLine())
		}

		if pay_cmd != "" {
			fz, _ = zi.Create(common.CFG.WebUI.PayCommandName)
			fz.Write([]byte(pay_cmd))
		}

		// Non-multisig transaction ...
		fz, _ = zi.Create("tx2sign.txt")
		fz.Write([]byte(hex.EncodeToString(tx.Serialize())))

		zi.Close()
		w.Header()["Content-Type"] = []string{"application/zip"}
		w.Write(buf.Bytes())
		return
	} else {
		err = "Bad request"
	}
error:
	s := load_template("send_error.html")
	write_html_head(w, r)
	s = strings.Replace(s, "<!--ERROR_MSG-->", err, 1)
	w.Write([]byte(s))
	write_html_tail(w)
}
示例#22
0
文件: fetchtx.go 项目: liudch/gocoin
// Download (and re-assemble) raw transaction from blockexplorer.com
func GetTxFromExplorer(txid *btc.Uint256) ([]byte, []byte) {
	url := "http://blockexplorer.com/rawtx/" + txid.String()
	r, er := http.Get(url)
	if er == nil && r.StatusCode == 200 {
		defer r.Body.Close()
		c, _ := ioutil.ReadAll(r.Body)
		var txx onetx
		er = json.Unmarshal(c[:], &txx)
		if er == nil {
			// This part looks weird, but this is how I solved seq=FFFFFFFF, if the field not present:
			for i := range txx.In {
				txx.In[i].Sequence = 0xffffffff
			}
			json.Unmarshal(c[:], &txx)
			// ... end of the weird solution

			tx := new(btc.Tx)
			tx.Version = txx.Ver
			tx.TxIn = make([]*btc.TxIn, len(txx.In))
			for i := range txx.In {
				tx.TxIn[i] = new(btc.TxIn)
				tx.TxIn[i].Input.Hash = btc.NewUint256FromString(txx.In[i].Prev_out.Hash).Hash
				tx.TxIn[i].Input.Vout = txx.In[i].Prev_out.N
				if txx.In[i].Prev_out.N == 0xffffffff &&
					txx.In[i].Prev_out.Hash == "0000000000000000000000000000000000000000000000000000000000000000" {
					tx.TxIn[i].ScriptSig, _ = hex.DecodeString(txx.In[i].Coinbase)
				} else {
					tx.TxIn[i].ScriptSig, _ = btc.DecodeScript(txx.In[i].ScriptSig)
				}
				tx.TxIn[i].Sequence = txx.In[i].Sequence
			}
			tx.TxOut = make([]*btc.TxOut, len(txx.Out))
			for i := range txx.Out {
				am, er := btc.StringToSatoshis(txx.Out[i].Value)
				if er != nil {
					fmt.Println("Incorrect BTC amount", txx.Out[i].Value, er.Error())
					return nil, nil
				}
				tx.TxOut[i] = new(btc.TxOut)
				tx.TxOut[i].Value = am
				tx.TxOut[i].Pk_script, _ = btc.DecodeScript(txx.Out[i].ScriptPubKey)
			}
			tx.Lock_time = txx.Lock_time
			rawtx := tx.Serialize()
			if txx.Size != uint(len(rawtx)) {
				fmt.Printf("Transaction size mismatch: %d expexted, %d decoded\n", txx.Size, len(rawtx))
				return nil, rawtx
			}
			curid := btc.NewSha2Hash(rawtx)
			if !curid.Equal(txid) {
				fmt.Println("The downloaded transaction does not match its ID.", txid.String())
				return nil, rawtx
			}
			return rawtx, rawtx
		} else {
			fmt.Println("json.Unmarshal:", er.Error())
		}
	} else {
		if er != nil {
			fmt.Println("http.Get:", er.Error())
		} else {
			fmt.Println("StatusCode=", r.StatusCode)
		}
	}
	return nil, nil
}