示例#1
0
// fetchLocationBySha look up the Tx sha information by name.
// Must be called with db lock held.
func (db *SqliteDb) fetchLocationBySha(txsha *btcwire.ShaHash) (blockidx int64, txoff int, txlen int, err error) {
	var row *sql.Row
	var blockid int64
	var ttxoff int
	var ttxlen int

	rowBytes := txsha.String()
	txop := db.txop(txFetchLocationByShaStmt)
	row = txop.QueryRow(rowBytes)

	err = row.Scan(&blockid, &ttxoff, &ttxlen)
	if err == sql.ErrNoRows {
		txop = db.txop(txtmpFetchLocationByShaStmt)
		row = txop.QueryRow(rowBytes)

		err = row.Scan(&blockid, &ttxoff, &ttxlen)
		if err == sql.ErrNoRows {
			err = btcdb.TxShaMissing
			return
		}
		if err != nil {
			log.Warnf("txtmp FetchLocationBySha: fail %v",
				err)
			return
		}
	}
	if err != nil {
		log.Warnf("FetchLocationBySha: fail %v", err)
		return
	}
	blockidx = blockid - 1
	txoff = ttxoff
	txlen = ttxlen
	return
}
示例#2
0
// FetchTxUsedBySha returns the used/spent buffer for a given transaction.
func (db *SqliteDb) FetchTxUsedBySha(txsha *btcwire.ShaHash) (spentbuf []byte, err error) {
	var row *sql.Row
	db.dbLock.Lock()
	defer db.dbLock.Unlock()

	rowBytes := txsha.String()
	txop := db.txop(txFetchUsedByShaStmt)
	row = txop.QueryRow(rowBytes)

	var databytes []byte
	err = row.Scan(&databytes)
	if err == sql.ErrNoRows {
		txop := db.txop(txtmpFetchUsedByShaStmt)
		row = txop.QueryRow(rowBytes)

		err = row.Scan(&databytes)
		if err == sql.ErrNoRows {
			err = btcdb.TxShaMissing
			return
		}
		if err != nil {
			log.Warnf("txtmp FetchLocationBySha: fail %v",
				err)
			return
		}
	}

	if err != nil {
		log.Warnf("FetchUsedBySha: fail %v", err)
		return
	}
	spentbuf = databytes
	return
}
示例#3
0
// VerboseGetRawTransaction sends the verbose version of a getrawtransaction
// request to receive details about a transaction.
func VerboseGetRawTransaction(rpc ServerConn, txsha *btcwire.ShaHash) (*btcjson.TxRawResult, *btcjson.Error) {
	// NewGetRawTransactionCmd cannot fail with a single optarg.
	cmd, _ := btcjson.NewGetRawTransactionCmd(<-NewJSONID, txsha.String(), 1)
	response := <-rpc.SendRequest(NewServerRequest(cmd))

	var resultData btcjson.TxRawResult
	_, jsonErr := response.FinishUnmarshal(&resultData)
	if jsonErr != nil {
		return nil, jsonErr
	}
	return &resultData, nil
}
示例#4
0
func notifySpentData(n ntfnChan, txhash *btcwire.ShaHash, index uint32,
	spender *btcutil.Tx) {

	var buf bytes.Buffer
	// Ignore Serialize's error, as writing to a bytes.buffer
	// cannot fail.
	spender.MsgTx().Serialize(&buf)
	txStr := hex.EncodeToString(buf.Bytes())

	ntfn := btcws.NewTxSpentNtfn(txhash.String(), int(index), txStr)
	n <- ntfn
}
示例#5
0
// GetRawTransactionAsync returns an instance of a type that can be used to get
// the result of the RPC at some future time by invoking the Receive function on
// the returned instance.
//
// See GetRawTransaction for the blocking version and more details.
func (c *Client) GetRawTransactionAsync(txHash *btcwire.ShaHash) FutureGetRawTransactionResult {
	hash := ""
	if txHash != nil {
		hash = txHash.String()
	}

	id := c.NextID()
	cmd, err := btcjson.NewGetRawTransactionCmd(id, hash, 0)
	if err != nil {
		return newFutureError(err)
	}

	return c.sendCmd(cmd)
}
示例#6
0
// GetBlockAsync returns an instance of a type that can be used to get the
// result of the RPC at some future time by invoking the Receive function on the
// returned instance.
//
// See GetBlock for the blocking version and more details.
func (c *Client) GetBlockAsync(blockHash *btcwire.ShaHash) FutureGetBlockResult {
	hash := ""
	if blockHash != nil {
		hash = blockHash.String()
	}

	id := c.NextID()
	cmd, err := btcjson.NewGetBlockCmd(id, hash, false)
	if err != nil {
		return newFutureError(err)
	}

	return c.sendCmd(cmd)
}
示例#7
0
// GetBlockVerboseAsync returns an instance of a type that can be used to get
// the result of the RPC at some future time by invoking the Receive function on
// the returned instance.
//
// See GetBlockVerbose for the blocking version and more details.
func (c *Client) GetBlockVerboseAsync(blockHash *btcwire.ShaHash, verboseTx bool) FutureGetBlockVerboseResult {
	hash := ""
	if blockHash != nil {
		hash = blockHash.String()
	}

	id := c.NextID()
	cmd, err := btcjson.NewGetBlockCmd(id, hash, true, verboseTx)
	if err != nil {
		return newFutureError(err)
	}

	return c.sendCmd(cmd)
}
示例#8
0
// insertTx inserts a tx hash and its associated data into the database.
// Must be called with db lock held.
func (db *SqliteDb) insertTx(txsha *btcwire.ShaHash, blockidx int64, txoff int, txlen int, usedbuf []byte) (err error) {

	tx := &db.txState
	if tx.tx == nil {
		err = db.startTx()
		if err != nil {
			return
		}
	}
	blockid := blockidx + 1
	txd := tTxInsertData{txsha: txsha, blockid: blockid, txoff: txoff, txlen: txlen, usedbuf: usedbuf}

	log.Tracef("inserting tx %v for block %v off %v len %v",
		txsha, blockid, txoff, txlen)

	rowBytes := txsha.String()

	var op int // which table to insert data into.
	if db.UseTempTX {
		var tblockid int64
		var ttxoff int
		var ttxlen int
		txop := db.txop(txFetchLocationByShaStmt)
		row := txop.QueryRow(rowBytes)
		err = row.Scan(&tblockid, &ttxoff, &ttxlen)
		if err != sql.ErrNoRows {
			// sha already present
			err = btcdb.DuplicateSha
			return
		}
		op = txtmpInsertStmt
	} else {
		op = txInsertStmt
	}

	txop := db.txop(op)
	_, err = txop.Exec(rowBytes, blockid, txoff, txlen, usedbuf)
	if err != nil {
		log.Warnf("failed to insert %v %v %v", txsha, blockid, err)
		return
	}
	if db.UseTempTX {
		db.TempTblSz++
	}

	// put in insert list for replay
	tx.txInsertList = append(tx.txInsertList, txd)

	return
}
示例#9
0
func notifySpentData(wallet walletChan, txhash *btcwire.ShaHash, index uint32,
	spender *btcutil.Tx) {

	var buf bytes.Buffer
	// Ignore Serialize's error, as writing to a bytes.buffer
	// cannot fail.
	spender.MsgTx().Serialize(&buf)
	txStr := hex.EncodeToString(buf.Bytes())

	// TODO(jrick): create a new notification in btcws and use that.
	ntfn := btcws.NewTxSpentNtfn(txhash.String(), int(index), txStr)
	mntfn, _ := ntfn.MarshalJSON()
	wallet <- mntfn
}
示例#10
0
// RescanEndBlockAsync returns an instance of a type that can be used to get
// the result of the RPC at some future time by invoking the Receive function on
// the returned instance.
//
// See RescanEndBlock for the blocking version and more details.
//
// NOTE: This is a btcd extension and requires a websocket connection.
func (c *Client) RescanEndBlockAsync(startBlock *btcwire.ShaHash,
	addresses []btcutil.Address, outpoints []*btcwire.OutPoint,
	endBlock *btcwire.ShaHash) FutureRescanResult {

	// Not supported in HTTP POST mode.
	if c.config.HttpPostMode {
		return newFutureError(ErrNotificationsNotSupported)
	}

	// Ignore the notification if the client is not interested in
	// notifications.
	if c.ntfnHandlers == nil {
		return newNilFutureResult()
	}

	// Convert block hashes to strings.
	var startBlockShaStr, endBlockShaStr string
	if startBlock != nil {
		startBlockShaStr = startBlock.String()
	}
	if endBlock != nil {
		endBlockShaStr = endBlock.String()
	}

	// Convert addresses to strings.
	addrs := make([]string, 0, len(addresses))
	for _, addr := range addresses {
		addrs = append(addrs, addr.String())
	}

	// Convert outpoints.
	ops := make([]btcws.OutPoint, 0, len(outpoints))
	for _, op := range outpoints {
		ops = append(ops, *btcws.NewOutPointFromWire(op))
	}

	id := c.NextID()
	cmd, err := btcws.NewRescanCmd(id, startBlockShaStr, addrs, ops,
		endBlockShaStr)
	if err != nil {
		return newFutureError(err)
	}

	return c.sendCmd(cmd)
}
示例#11
0
// createTxRawResult converts the passed transaction and associated parameters
// to a raw transaction JSON object.
func createTxRawResult(net btcwire.BitcoinNet, txSha string, mtx *btcwire.MsgTx, blk *btcutil.Block, maxidx int64, blksha *btcwire.ShaHash) (*btcjson.TxRawResult, error) {
	mtxHex, err := messageToHex(mtx)
	if err != nil {
		return nil, err
	}

	vin, err := createVinList(mtx)
	if err != nil {
		return nil, err
	}
	vout, err := createVoutList(mtx, net)
	if err != nil {
		return nil, err
	}

	txReply := &btcjson.TxRawResult{
		Hex:      mtxHex,
		Txid:     txSha,
		Vout:     vout,
		Vin:      vin,
		Version:  mtx.Version,
		LockTime: mtx.LockTime,
	}

	if blk != nil {
		blockHeader := &blk.MsgBlock().Header
		idx := blk.Height()

		// This is not a typo, they are identical in bitcoind as well.
		txReply.Time = blockHeader.Timestamp.Unix()
		txReply.Blocktime = blockHeader.Timestamp.Unix()
		txReply.BlockHash = blksha.String()
		txReply.Confirmations = uint64(1 + maxidx - idx)
	}

	return txReply, nil
}
示例#12
0
// handleGetBlock implements the getblock command.
func handleGetBlock(s *rpcServer, cmd btcjson.Cmd) (interface{}, error) {
	c := cmd.(*btcjson.GetBlockCmd)
	sha, err := btcwire.NewShaHashFromStr(c.Hash)
	if err != nil {
		rpcsLog.Errorf("Error generating sha: %v", err)
		return nil, btcjson.ErrBlockNotFound
	}
	blk, err := s.server.db.FetchBlockBySha(sha)
	if err != nil {
		rpcsLog.Errorf("Error fetching sha: %v", err)
		return nil, btcjson.ErrBlockNotFound
	}

	// When the verbose flag isn't set, simply return the network-serialized
	// block as a hex-encoded string.
	if !c.Verbose {
		blkHex, err := messageToHex(blk.MsgBlock())
		if err != nil {
			return nil, err
		}
		return blkHex, nil
	}

	// The verbose flag is set, so generate the JSON object and return it.
	buf, err := blk.Bytes()
	if err != nil {
		rpcsLog.Errorf("Error fetching block: %v", err)
		return nil, btcjson.Error{
			Code:    btcjson.ErrInternal.Code,
			Message: err.Error(),
		}
	}
	idx := blk.Height()
	_, maxidx, err := s.server.db.NewestSha()
	if err != nil {
		rpcsLog.Errorf("Cannot get newest sha: %v", err)
		return nil, btcjson.ErrBlockNotFound
	}

	blockHeader := &blk.MsgBlock().Header
	blockReply := btcjson.BlockResult{
		Hash:          c.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,
		Size:          len(buf),
		Bits:          strconv.FormatInt(int64(blockHeader.Bits), 16),
		Difficulty:    getDifficultyRatio(blockHeader.Bits),
	}

	if !c.VerboseTx {
		txList, _ := blk.TxShas()

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

		blockReply.Tx = txNames
	} else {
		txns := blk.Transactions()
		rawTxns := make([]btcjson.TxRawResult, len(txns))
		for i, tx := range txns {
			txSha := tx.Sha().String()
			mtx := tx.MsgTx()

			rawTxn, err := createTxRawResult(s.server.btcnet, txSha,
				mtx, blk, maxidx, sha)
			if err != nil {
				rpcsLog.Errorf("Cannot create TxRawResult for "+
					"transaction %s: %v", txSha, err)
				return nil, err
			}
			rawTxns[i] = *rawTxn
		}
		blockReply.RawTx = rawTxns
	}

	// Get next block unless we are already at the top.
	if idx < maxidx {
		var shaNext *btcwire.ShaHash
		shaNext, err = s.server.db.FetchBlockShaByHeight(int64(idx + 1))
		if err != nil {
			rpcsLog.Errorf("No next block: %v", err)
			return nil, btcjson.ErrBlockNotFound
		}
		blockReply.NextHash = shaNext.String()
	}

	return blockReply, nil
}
示例#13
0
// GetRawTransaction returns a future representing a pending GetRawTransaction
// command for txsha.. When the result of the request is required it may be
// collected with GetRawTRansactionAsyncResult.
func GetRawTransactionAsync(rpc ServerConn, txsha *btcwire.ShaHash) chan RawRPCResponse {
	// NewGetRawTransactionCmd cannot fail with no optargs.
	cmd, _ := btcjson.NewGetRawTransactionCmd(<-NewJSONID, txsha.String())

	return rpc.SendRequest(NewServerRequest(cmd))
}
示例#14
0
// handleGetBlock implements the getblock command.
func handleGetBlock(s *rpcServer, cmd btcjson.Cmd, walletNotification chan []byte) (interface{}, error) {
	c := cmd.(*btcjson.GetBlockCmd)
	sha, err := btcwire.NewShaHashFromStr(c.Hash)
	if err != nil {
		log.Errorf("RPCS: Error generating sha: %v", err)
		return nil, btcjson.ErrBlockNotFound
	}
	blk, err := s.server.db.FetchBlockBySha(sha)
	if err != nil {
		log.Errorf("RPCS: Error fetching sha: %v", err)
		return nil, btcjson.ErrBlockNotFound
	}
	idx := blk.Height()
	buf, err := blk.Bytes()
	if err != nil {
		log.Errorf("RPCS: Error fetching block: %v", err)
		return nil, btcjson.ErrBlockNotFound
	}

	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 nil, btcjson.ErrBlockNotFound
	}

	blockHeader := &blk.MsgBlock().Header
	blockReply := btcjson.BlockResult{
		Hash:          c.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 {
		var shaNext *btcwire.ShaHash
		shaNext, err = s.server.db.FetchBlockShaByHeight(int64(idx + 1))
		if err != nil {
			log.Errorf("RPCS: No next block: %v", err)
			return nil, btcjson.ErrBlockNotFound
		}
		blockReply.NextHash = shaNext.String()
	}

	return blockReply, nil
}