// This example demonstrates creating a script which pays to a bitcoin 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 btcutil.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 := "12gpXQVcCL2qhTNQgyLVdCFG2Qs2px98nV"
	address, err := btcutil.DecodeAddress(addressStr, &btcnet.MainNetParams)
	if err != nil {
		fmt.Println(err)
		return
	}

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

	disasm, err := btcscript.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
}
Exemple #2
0
// createVoutList returns a slice of JSON objects for the outputs of the passed
// transaction.
func createVoutList(mtx *btcwire.MsgTx, net btcwire.BitcoinNet) ([]btcjson.Vout, error) {
	voutList := make([]btcjson.Vout, len(mtx.TxOut))
	for i, v := range mtx.TxOut {
		voutList[i].N = i
		voutList[i].Value = float64(v.Value) / float64(btcutil.SatoshiPerBitcoin)

		disbuf, err := btcscript.DisasmString(v.PkScript)
		if err != nil {
			return nil, btcjson.Error{
				Code:    btcjson.ErrInternal.Code,
				Message: err.Error(),
			}
		}
		voutList[i].ScriptPubKey.Asm = disbuf
		voutList[i].ScriptPubKey.Hex = hex.EncodeToString(v.PkScript)

		// Ignore the error here since an error means the script
		// couldn't parse and there is no additional information about
		// it anyways.
		scriptClass, addrs, reqSigs, _ := btcscript.ExtractPkScriptAddrs(v.PkScript, net)
		voutList[i].ScriptPubKey.Type = scriptClass.String()
		voutList[i].ScriptPubKey.ReqSigs = reqSigs

		if addrs == nil {
			voutList[i].ScriptPubKey.Addresses = nil
		} else {
			voutList[i].ScriptPubKey.Addresses = make([]string, len(addrs))
			for j, addr := range addrs {
				voutList[i].ScriptPubKey.Addresses[j] = addr.EncodeAddress()
			}
		}
	}

	return voutList, nil
}
Exemple #3
0
// createVinList returns a slice of JSON objects for the inputs of the passed
// transaction.
func createVinList(mtx *btcwire.MsgTx) ([]btcjson.Vin, error) {
	tx := btcutil.NewTx(mtx)
	vinList := make([]btcjson.Vin, len(mtx.TxIn))
	for i, v := range mtx.TxIn {
		if btcchain.IsCoinBase(tx) {
			vinList[i].Coinbase = hex.EncodeToString(v.SignatureScript)
		} else {
			vinList[i].Txid = v.PreviousOutpoint.Hash.String()
			vinList[i].Vout = int(v.PreviousOutpoint.Index)

			disbuf, err := btcscript.DisasmString(v.SignatureScript)
			if err != nil {
				return nil, btcjson.Error{
					Code:    btcjson.ErrInternal.Code,
					Message: err.Error(),
				}
			}
			vinList[i].ScriptSig = new(btcjson.ScriptSig)
			vinList[i].ScriptSig.Asm = disbuf
			vinList[i].ScriptSig.Hex = hex.EncodeToString(v.SignatureScript)
		}
		vinList[i].Sequence = v.Sequence
	}

	return vinList, nil
}
func PayToAddrScript(addressStr string) {
	// Parse the address to send the coins to into a btcutil.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.
	address, err := btcutil.DecodeAddress(addressStr, &btcnet.MainNetParams)
	handle(err)

	// Create a public key script that pays to the address.
	script, err := btcscript.PayToAddrScript(address)
	handle(err)
	fmt.Printf("Script Hex: %x\n", script)

	disasm, err := btcscript.DisasmString(script)
	handle(err)
	fmt.Println("Script Disassembly:", disasm)
}
Exemple #5
0
// handleDecodeScript handles decodescript commands.
func handleDecodeScript(s *rpcServer, cmd btcjson.Cmd) (interface{}, error) {
	c := cmd.(*btcjson.DecodeScriptCmd)

	// Convert the hex script to bytes.
	script, err := hex.DecodeString(c.HexScript)
	if err != nil {
		return nil, btcjson.Error{
			Code: btcjson.ErrInvalidParameter.Code,
			Message: fmt.Sprintf("argument must be hexadecimal "+
				"string (not %q)", c.HexScript),
		}
	}

	// The disassembled string will contain [error] inline if the script
	// doesn't fully parse, so ignore the error here.
	disbuf, _ := btcscript.DisasmString(script)

	// Get information about the script.
	// Ignore the error here since an error means the script couldn't parse
	// and there is no additinal information about it anyways.
	net := s.server.btcnet
	scriptClass, addrs, reqSigs, _ := btcscript.ExtractPkScriptAddrs(script, net)
	addresses := make([]string, len(addrs))
	for i, addr := range addrs {
		addresses[i] = addr.EncodeAddress()
	}

	// Convert the script itself to a pay-to-script-hash address.
	p2sh, err := btcutil.NewAddressScriptHash(script, net)
	if err != nil {
		return nil, btcjson.Error{
			Code:    btcjson.ErrInternal.Code,
			Message: err.Error(),
		}
	}

	// Generate and return the reply.
	reply := btcjson.DecodeScriptResult{
		Asm:       disbuf,
		ReqSigs:   reqSigs,
		Type:      scriptClass.String(),
		Addresses: addresses,
		P2sh:      p2sh.EncodeAddress(),
	}
	return reply, nil
}
Exemple #6
0
// jsonRPCRead is the main function that handles reading messages, getting
// the data the message requests, and writing the reply.
func jsonRPCRead(w http.ResponseWriter, r *http.Request, s *rpcServer) {
	_ = spew.Dump
	r.Close = true
	if atomic.LoadInt32(&s.shutdown) != 0 {
		return
	}
	var rawReply btcjson.Reply
	body, err := btcjson.GetRaw(r.Body)
	if err != nil {
		log.Errorf("[RPCS] Error getting json message: %v", err)
		return
	}
	var message btcjson.Message
	err = json.Unmarshal(body, &message)
	if err != nil {
		log.Errorf("[RPCS] Error unmarshalling json message: %v", err)
		jsonError := btcjson.Error{
			Code:    -32700,
			Message: "Parse error",
		}

		rawReply = btcjson.Reply{
			Result: nil,
			Error:  &jsonError,
			Id:     nil,
		}
		log.Tracef("[RPCS] reply: %v", rawReply)
		msg, err := btcjson.MarshallAndSend(rawReply, w)
		if err != nil {
			log.Errorf(msg)
			return
		}
		log.Debugf(msg)
		return

	}
	log.Tracef("[RPCS] received: %v", message)

	// Deal with commands
	switch message.Method {
	case "stop":
		rawReply = btcjson.Reply{
			Result: "btcd stopping.",
			Error:  nil,
			Id:     &message.Id,
		}
		s.server.Stop()
	case "getblockcount":
		_, maxidx, _ := s.server.db.NewestSha()
		rawReply = btcjson.Reply{
			Result: maxidx,
			Error:  nil,
			Id:     &message.Id,
		}
	// btcd does not do mining so we can hardcode replies here.
	case "getgenerate":
		rawReply = btcjson.Reply{
			Result: false,
			Error:  nil,
			Id:     &message.Id,
		}
	case "setgenerate":
		rawReply = btcjson.Reply{
			Result: nil,
			Error:  nil,
			Id:     &message.Id,
		}
	case "gethashespersec":
		rawReply = btcjson.Reply{
			Result: 0,
			Error:  nil,
			Id:     &message.Id,
		}
	case "getblockhash":
		var f interface{}
		err = json.Unmarshal(body, &f)
		m := f.(map[string]interface{})
		var idx float64
		for _, v := range m {
			switch vv := v.(type) {
			case []interface{}:
				for _, u := range vv {
					idx, _ = u.(float64)
				}
			default:
			}
		}
		sha, err := s.server.db.FetchBlockShaByHeight(int64(idx))
		if err != nil {
			log.Errorf("[RCPS] Error getting block: %v", err)
			jsonError := btcjson.Error{
				Code:    -1,
				Message: "Block number out of range.",
			}

			rawReply = btcjson.Reply{
				Result: nil,
				Error:  &jsonError,
				Id:     &message.Id,
			}
			log.Tracef("[RPCS] reply: %v", rawReply)
			break

		}

		rawReply = btcjson.Reply{
			Result: sha.String(),
			Error:  nil,
			Id:     &message.Id,
		}
	case "getblock":
		var f interface{}
		err = json.Unmarshal(body, &f)
		m := f.(map[string]interface{})
		var hash string
		for _, v := range m {
			switch vv := v.(type) {
			case []interface{}:
				for _, u := range vv {
					hash, _ = u.(string)
				}
			default:
			}
		}
		sha, err := btcwire.NewShaHashFromStr(hash)
		if err != nil {
			log.Errorf("[RPCS] Error generating sha: %v", err)
			jsonError := btcjson.Error{
				Code:    -5,
				Message: "Block not found",
			}

			rawReply = btcjson.Reply{
				Result: nil,
				Error:  &jsonError,
				Id:     &message.Id,
			}
			log.Tracef("[RPCS] reply: %v", rawReply)
			break
		}
		blk, err := s.server.db.FetchBlockBySha(sha)
		if err != nil {
			log.Errorf("[RPCS] Error fetching sha: %v", err)
			jsonError := btcjson.Error{
				Code:    -5,
				Message: "Block not found",
			}

			rawReply = btcjson.Reply{
				Result: nil,
				Error:  &jsonError,
				Id:     &message.Id,
			}
			log.Tracef("[RPCS] reply: %v", rawReply)
			break
		}
		idx := blk.Height()
		buf, err := blk.Bytes()
		if err != nil {
			log.Errorf("[RPCS] Error fetching block: %v", err)
			jsonError := btcjson.Error{
				Code:    -5,
				Message: "Block not found",
			}

			rawReply = btcjson.Reply{
				Result: nil,
				Error:  &jsonError,
				Id:     &message.Id,
			}
			log.Tracef("[RPCS] reply: %v", rawReply)
			break
		}

		txList, _ := blk.TxShas()

		txNames := make([]string, len(txList))
		for i, v := range txList {
			txNames[i] = v.String()
		}

		_, maxidx, err := s.server.db.NewestSha()
		if err != nil {
			log.Errorf("[RPCS] Cannot get newest sha: %v", err)
			return
		}

		blockHeader := &blk.MsgBlock().Header
		blockReply := btcjson.BlockResult{
			Hash:          hash,
			Version:       blockHeader.Version,
			MerkleRoot:    blockHeader.MerkleRoot.String(),
			PreviousHash:  blockHeader.PrevBlock.String(),
			Nonce:         blockHeader.Nonce,
			Time:          blockHeader.Timestamp.Unix(),
			Confirmations: uint64(1 + maxidx - idx),
			Height:        idx,
			Tx:            txNames,
			Size:          len(buf),
			Bits:          strconv.FormatInt(int64(blockHeader.Bits), 16),
			Difficulty:    getDifficultyRatio(blockHeader.Bits),
		}

		// Get next block unless we are already at the top.
		if idx < maxidx {
			shaNext, err := s.server.db.FetchBlockShaByHeight(int64(idx + 1))
			if err != nil {
				log.Errorf("[RPCS] No next block: %v", err)
			} else {
				blockReply.NextHash = shaNext.String()
			}
		}

		rawReply = btcjson.Reply{
			Result: blockReply,
			Error:  nil,
			Id:     &message.Id,
		}
	case "getrawtransaction":
		var f interface{}
		err = json.Unmarshal(body, &f)
		m := f.(map[string]interface{})
		var tx string
		var verbose float64
		for _, v := range m {
			switch vv := v.(type) {
			case []interface{}:
				for _, u := range vv {
					switch uu := u.(type) {
					case string:
						tx = uu
					case float64:
						verbose = uu
					default:
					}
				}
			default:
			}
		}

		if int(verbose) != 1 {
			// Don't return details
			// not used yet
		} else {
			txSha, _ := btcwire.NewShaHashFromStr(tx)
			var txS *btcwire.MsgTx
			txList, err := s.server.db.FetchTxBySha(txSha)
			if err != nil {
				log.Errorf("[RPCS] Error fetching tx: %v", err)
				jsonError := btcjson.Error{
					Code:    -5,
					Message: "No information available about transaction",
				}

				rawReply = btcjson.Reply{
					Result: nil,
					Error:  &jsonError,
					Id:     &message.Id,
				}
				log.Tracef("[RPCS] reply: %v", rawReply)
				break
			}

			lastTx := len(txList) - 1
			txS = txList[lastTx].Tx
			blksha := txList[lastTx].BlkSha
			blk, err := s.server.db.FetchBlockBySha(blksha)
			if err != nil {
				log.Errorf("[RPCS] Error fetching sha: %v", err)
				jsonError := btcjson.Error{
					Code:    -5,
					Message: "Block not found",
				}

				rawReply = btcjson.Reply{
					Result: nil,
					Error:  &jsonError,
					Id:     &message.Id,
				}
				log.Tracef("[RPCS] reply: %v", rawReply)
				break
			}
			idx := blk.Height()

			txOutList := txS.TxOut
			voutList := make([]btcjson.Vout, len(txOutList))

			txInList := txS.TxIn
			vinList := make([]btcjson.Vin, len(txInList))

			for i, v := range txInList {
				vinList[i].Sequence = float64(v.Sequence)
				disbuf, _ := btcscript.DisasmString(v.SignatureScript)
				vinList[i].ScriptSig.Asm = strings.Replace(disbuf, " ", "", -1)
				vinList[i].Vout = i + 1
				log.Debugf(disbuf)
			}

			for i, v := range txOutList {
				voutList[i].N = i
				voutList[i].Value = float64(v.Value) / 100000000
				isbuf, _ := btcscript.DisasmString(v.PkScript)
				voutList[i].ScriptPubKey.Asm = isbuf
				voutList[i].ScriptPubKey.ReqSig = strings.Count(isbuf, "OP_CHECKSIG")
				_, addr, err := btcscript.ScriptToAddress(v.PkScript)
				if err != nil {
					log.Errorf("[RPCS] Error getting address for %v: %v", txSha, err)
				} else {
					addrList := make([]string, 1)
					addrList[0] = addr
					voutList[i].ScriptPubKey.Addresses = addrList
				}
			}

			_, maxidx, err := s.server.db.NewestSha()
			if err != nil {
				log.Errorf("[RPCS] Cannot get newest sha: %v", err)
				return
			}
			confirmations := uint64(1 + maxidx - idx)

			blockHeader := &blk.MsgBlock().Header
			txReply := btcjson.TxRawResult{
				Txid:     tx,
				Vout:     voutList,
				Vin:      vinList,
				Version:  txS.Version,
				LockTime: txS.LockTime,
				// This is not a typo, they are identical in
				// bitcoind as well.
				Time:          blockHeader.Timestamp.Unix(),
				Blocktime:     blockHeader.Timestamp.Unix(),
				BlockHash:     blksha.String(),
				Confirmations: confirmations,
			}
			rawReply = btcjson.Reply{
				Result: txReply,
				Error:  nil,
				Id:     &message.Id,
			}
		}
	case "decoderawtransaction":
		var f interface{}
		err = json.Unmarshal(body, &f)
		m := f.(map[string]interface{})
		var hash string
		for _, v := range m {
			switch vv := v.(type) {
			case []interface{}:
				for _, u := range vv {
					hash, _ = u.(string)
				}
			default:
			}
		}
		spew.Dump(hash)
		txReply := btcjson.TxRawDecodeResult{}
		rawReply = btcjson.Reply{
			Result: txReply,
			Error:  nil,
			Id:     &message.Id,
		}
	default:
		jsonError := btcjson.Error{
			Code:    -32601,
			Message: "Method not found",
		}
		rawReply = btcjson.Reply{
			Result: nil,
			Error:  &jsonError,
			Id:     &message.Id,
		}
	}

	msg, err := btcjson.MarshallAndSend(rawReply, w)
	if err != nil {
		log.Errorf(msg)
		return
	}
	log.Debugf(msg)
	return
}
Exemple #7
0
// handleGetRawTransaction implements the getrawtransaction command.
func handleGetRawTransaction(s *rpcServer, cmd btcjson.Cmd, walletNotification chan []byte) (interface{}, error) {
	c := cmd.(*btcjson.GetRawTransactionCmd)
	if c.Verbose {
		// TODO: check error code. tx is not checked before
		// this point.
		txSha, _ := btcwire.NewShaHashFromStr(c.Txid)
		txList, err := s.server.db.FetchTxBySha(txSha)
		if err != nil {
			log.Errorf("RPCS: Error fetching tx: %v", err)
			return nil, btcjson.ErrNoTxInfo
		}

		lastTx := len(txList) - 1
		txS := txList[lastTx].Tx
		blksha := txList[lastTx].BlkSha
		blk, err := s.server.db.FetchBlockBySha(blksha)
		if err != nil {
			log.Errorf("RPCS: Error fetching sha: %v", err)
			return nil, btcjson.ErrBlockNotFound
		}
		idx := blk.Height()

		txOutList := txS.TxOut
		voutList := make([]btcjson.Vout, len(txOutList))

		txInList := txS.TxIn
		vinList := make([]btcjson.Vin, len(txInList))

		for i, v := range txInList {
			vinList[i].Sequence = float64(v.Sequence)
			disbuf, _ := btcscript.DisasmString(v.SignatureScript)
			vinList[i].ScriptSig.Asm = strings.Replace(disbuf, " ", "", -1)
			vinList[i].Vout = i + 1
			log.Debugf(disbuf)
		}

		for i, v := range txOutList {
			voutList[i].N = i
			voutList[i].Value = float64(v.Value) / 100000000
			isbuf, _ := btcscript.DisasmString(v.PkScript)
			voutList[i].ScriptPubKey.Asm = isbuf
			voutList[i].ScriptPubKey.ReqSig = strings.Count(isbuf, "OP_CHECKSIG")
			_, addrhash, err := btcscript.ScriptToAddrHash(v.PkScript)
			if err != nil {
				// TODO: set and return error?
				log.Errorf("RPCS: Error getting address hash for %v: %v", txSha, err)
			}
			if addr, err := btcutil.EncodeAddress(addrhash, s.server.btcnet); err != nil {
				// TODO: set and return error?
				addrList := make([]string, 1)
				addrList[0] = addr
				voutList[i].ScriptPubKey.Addresses = addrList
			}
		}

		_, maxidx, err := s.server.db.NewestSha()
		if err != nil {
			log.Errorf("RPCS: Cannot get newest sha: %v", err)
			return nil, btcjson.ErrNoNewestBlockInfo
		}
		confirmations := uint64(1 + maxidx - idx)

		blockHeader := &blk.MsgBlock().Header
		txReply := btcjson.TxRawResult{
			Txid:     c.Txid,
			Vout:     voutList,
			Vin:      vinList,
			Version:  txS.Version,
			LockTime: txS.LockTime,
			// This is not a typo, they are identical in
			// bitcoind as well.
			Time:          blockHeader.Timestamp.Unix(),
			Blocktime:     blockHeader.Timestamp.Unix(),
			BlockHash:     blksha.String(),
			Confirmations: confirmations,
		}
		return txReply, nil
	} else {
		// Don't return details
		// not used yet
		return nil, nil
	}
}