Beispiel #1
0
// RecordMinedTx searches through each account's TxStore, searching for a
// sent transaction with the same txid as from a txmined notification.  If
// the transaction IDs match, the record in the TxStore is updated with
// the full information about the newly-mined tx, and the TxStore is
// scheduled to be written to disk..
func (am *AccountManager) RecordMinedTx(txid *btcwire.ShaHash,
	blkhash *btcwire.ShaHash, blkheight int32, blkindex int,
	blktime int64) error {

	for _, a := range am.AllAccounts() {
		// Search in reverse order.  Since more recently-created
		// transactions are appended to the end of the store, it's
		// more likely to find it when searching from the end.
		for i := len(a.TxStore) - 1; i >= 0; i-- {
			sendtx, ok := a.TxStore[i].(*tx.SendTx)
			if ok {
				if bytes.Equal(txid.Bytes(), sendtx.TxID[:]) {
					copy(sendtx.BlockHash[:], blkhash.Bytes())
					sendtx.BlockHeight = blkheight
					sendtx.BlockIndex = int32(blkindex)
					sendtx.BlockTime = blktime

					am.ds.ScheduleTxStoreWrite(a)

					return nil
				}
			}
		}
	}

	return errors.New("txid does not match any recorded sent transaction")
}
Beispiel #2
0
// hashMerkleBranches takes two hashes, treated as the left and right tree
// nodes, and returns the hash of their concatenation.  This is a helper
// function used to during generatation of a merkle tree.
func hashMerkleBranches(left *btcwire.ShaHash, right *btcwire.ShaHash) *btcwire.ShaHash {
	// Concatenate the left and right nodes.
	var sha [btcwire.HashSize * 2]byte
	copy(sha[:btcwire.HashSize], left.Bytes())
	copy(sha[btcwire.HashSize:], right.Bytes())

	// Create a new sha hash from the double sha 256.  Ignore the error
	// here since SetBytes can't fail here due to the fact DoubleSha256
	// always returns a []byte of the right size regardless of input.
	newSha, _ := btcwire.NewShaHash(btcwire.DoubleSha256(sha[:]))
	return newSha
}
Beispiel #3
0
// ShaHashToBig converts a btcwire.ShaHash into a big.Int that can be used to
// perform math comparisons.
func ShaHashToBig(hash *btcwire.ShaHash) *big.Int {
	// A ShaHash is in little-endian, but the big package wants the bytes
	// in big-endian.  Reverse them.  ShaHash.Bytes makes a copy, so it
	// is safe to modify the returned buffer.
	buf := hash.Bytes()
	blen := len(buf)
	for i := 0; i < blen/2; i++ {
		buf[i], buf[blen-1-i] = buf[blen-1-i], buf[i]
	}

	return new(big.Int).SetBytes(buf)
}
Beispiel #4
0
func (db *LevelDb) setBlk(sha *btcwire.ShaHash, blkHeight int64, buf []byte) {
	// serialize
	var lw [8]byte
	binary.LittleEndian.PutUint64(lw[0:8], uint64(blkHeight))

	shaKey := shaBlkToKey(sha)
	blkKey := int64ToKey(blkHeight)

	shaB := sha.Bytes()
	blkVal := make([]byte, len(shaB)+len(buf))
	copy(blkVal[0:], shaB)
	copy(blkVal[len(shaB):], buf)

	db.lBatch().Put(shaKey, lw[:])
	db.lBatch().Put(blkKey, blkVal)
}
Beispiel #5
0
// blkExistsSha looks up the given block hash
// returns true if it is present in the database.
// CALLED WITH LOCK HELD
func (db *SqliteDb) blkExistsSha(sha *btcwire.ShaHash) bool {
	var pver uint32

	row := db.blkStmts[blkExistsSha].QueryRow(sha.Bytes())
	err := row.Scan(&pver)

	if err == sql.ErrNoRows {
		return false
	}

	if err != nil {
		// ignore real errors?
		log.Warnf("blkExistsSha: fail %v", err)
		return false
	}
	return true
}
Beispiel #6
0
// insertSha stores a block hash and its associated data block with a
// previous sha of `prevSha' and a version of `pver'.
// insertSha shall be called with db lock held
func (db *SqliteDb) insertBlockData(sha *btcwire.ShaHash, prevSha *btcwire.ShaHash, pver uint32, buf []byte) (blockid int64, err error) {
	tx := &db.txState
	if tx.tx == nil {
		err = db.startTx()
		if err != nil {
			return
		}
	}

	var prevOk bool
	var blkid int64

	prevOk = db.blkExistsSha(prevSha) // exists -> ok
	if !prevOk {
		return 0, btcdb.PrevShaMissing
	}

	result, err := db.blkStmts[blkInsertSha].Exec(sha.Bytes(), pver, buf)
	if err != nil {
		return
	}

	blkid, err = result.LastInsertId()
	if err != nil {
		return 0, err
	}
	blkid -= 1 // skew between btc blockid and sql

	// Because we don't know know what the last idx is, we don't
	// cache unless already cached
	if db.lastBlkShaCached == true {
		db.lastBlkSha = *sha
		db.lastBlkIdx++
	}

	bid := tBlockInsertData{*sha, pver, buf}
	tx.txInsertList = append(tx.txInsertList, bid)
	tx.txDataSz += len(buf)

	blockid = blkid
	return
}
Beispiel #7
0
// RecordMinedTx searches through each account's TxStore, searching for a
// sent transaction with the same txid as from a txmined notification.  If
// the transaction IDs match, the record in the TxStore is updated with
// the full information about the newly-mined tx, and the TxStore is
// scheduled to be written to disk..
func (store *AccountStore) RecordMinedTx(txid *btcwire.ShaHash,
	blkhash *btcwire.ShaHash, blkheight int32, blkindex int,
	blktime int64) error {

	store.RLock()
	defer store.RUnlock()

	for _, account := range store.accounts {
		// The tx stores will be searched through while holding the
		// reader lock, and the writer will only be grabbed if necessary.
		account.TxStore.RLock()

		// Search in reverse order.  Since more recently-created
		// transactions are appended to the end of the store, it's
		// more likely to find it when searching from the end.
		for i := len(account.TxStore.s) - 1; i >= 0; i-- {
			sendtx, ok := account.TxStore.s[i].(*tx.SendTx)
			if ok {
				if bytes.Equal(txid.Bytes(), sendtx.TxID[:]) {
					account.TxStore.RUnlock()

					account.TxStore.Lock()
					copy(sendtx.BlockHash[:], blkhash.Bytes())
					sendtx.BlockHeight = blkheight
					sendtx.BlockIndex = int32(blkindex)
					sendtx.BlockTime = blktime
					account.TxStore.Unlock()

					account.ScheduleTxStoreWrite()

					return nil
				}
			}
		}

		account.TxStore.RUnlock()
	}

	return errors.New("txid does not match any recorded sent transaction")
}
Beispiel #8
0
// fetchSha returns the datablock and pver for the given ShaHash.
func (db *SqliteDb) fetchSha(sha btcwire.ShaHash) (buf []byte, pver uint32,
	blkid int64, err error) {

	db.dbLock.Lock()
	defer db.dbLock.Unlock()

	row := db.blkStmts[blkFetchSha].QueryRow(sha.Bytes())

	var blockidx int64
	var databytes []byte
	err = row.Scan(&pver, &databytes, &blockidx)
	if err == sql.ErrNoRows {
		return // no warning
	}
	if err != nil {
		log.Warnf("fail 2 %v", err)
		return
	}
	buf = databytes
	blkid = blockidx - 1 // skew between btc blockid and sql
	return
}
Beispiel #9
0
func (db *LevelDb) setBlk(sha *btcwire.ShaHash, blkHeight int64, buf []byte) error {

	// serialize
	var lw bytes.Buffer
	err := binary.Write(&lw, binary.LittleEndian, blkHeight)
	if err != nil {
		err = fmt.Errorf("Write Fail")
		return err
	}
	shaKey := shaBlkToKey(sha)

	blkKey := int64ToKey(blkHeight)

	shaB := sha.Bytes()
	blkVal := make([]byte, len(shaB)+len(buf))
	copy(blkVal[0:], shaB)
	copy(blkVal[len(shaB):], buf)

	db.lBatch().Put(shaKey, lw.Bytes())

	db.lBatch().Put(blkKey, blkVal)

	return nil
}
Beispiel #10
0
func shaSpentTxToKey(sha *btcwire.ShaHash) []byte {
	shaB := sha.Bytes()
	shaB = append(shaB, "sx"...)
	return shaB
}
Beispiel #11
0
func shaBlkToKey(sha *btcwire.ShaHash) []byte {
	shaB := sha.Bytes()
	return shaB
}
Beispiel #12
0
// AddShaHash adds the passed btcwire.ShaHash to the Filter.
//
// This function is safe for concurrent access.
func (bf *Filter) AddShaHash(sha *btcwire.ShaHash) {
	bf.mtx.Lock()
	bf.add(sha.Bytes())
	bf.mtx.Unlock()
}
Beispiel #13
0
// DropAfterBlockBySha will remove any blocks from the database after the given block.
// It terminates any existing transaction and performs its operations in an
// atomic transaction, it is terminated (committed) before exit.
func (db *SqliteDb) DropAfterBlockBySha(sha btcwire.ShaHash) (err error) {
	var row *sql.Row
	db.dbLock.Lock()
	defer db.dbLock.Unlock()

	db.InvalidateCache()

	// This is a destructive operation and involves multiple requests
	// so requires a transaction, terminate any transaction to date
	// and start a new transaction
	err = db.endTx(true)
	if err != nil {
		return err
	}
	err = db.startTx()
	if err != nil {
		return err
	}

	// also drop any cached sha data
	db.lastBlkShaCached = false

	querystr := "SELECT blockid FROM block WHERE key = ?;"

	tx := &db.txState
	row = tx.tx.QueryRow(querystr, sha.Bytes())

	var blockidx uint64
	err = row.Scan(&blockidx)
	if err != nil {
		// XXX
		db.endTx(false)
		return err
	}

	_, err = tx.tx.Exec("DELETE FROM txtmp WHERE blockid > ?", blockidx)
	if err != nil {
		// XXX
		db.endTx(false)
		return err
	}

	_, err = tx.tx.Exec("DELETE FROM tx WHERE blockid > ?", blockidx)
	if err != nil {
		// XXX
		db.endTx(false)
		return err
	}

	// delete from block last in case of foreign keys
	_, err = tx.tx.Exec("DELETE FROM block WHERE blockid > ?", blockidx)
	if err != nil {
		// XXX
		db.endTx(false)
		return err
	}

	err = db.endTx(true)
	if err != nil {
		return err
	}
	return
}