示例#1
0
文件: mempool.go 项目: kingpro/btcd
// calcMinRelayFee retuns the minimum transaction fee required for the passed
// transaction to be accepted into the memory pool and relayed.
func calcMinRelayFee(tx *btcutil.Tx) int64 {
	// Most miners allow a free transaction area in blocks they mine to go
	// alongside the area used for high-priority transactions as well as
	// transactions with fees.  A transaction size of up to 1000 bytes is
	// considered safe to go into this section.  Further, the minimum fee
	// calculated below on its own would encourage several small
	// transactions to avoid fees rather than one single larger transaction
	// which is more desirable.  Therefore, as long as the size of the
	// transaction does not exceeed 1000 less than the reserved space for
	// high-priority transactions, don't require a fee for it.
	serializedLen := int64(tx.MsgTx().SerializeSize())
	if serializedLen < (defaultBlockPrioritySize - 1000) {
		return 0
	}

	// Calculate the minimum fee for a transaction to be allowed into the
	// mempool and relayed by scaling the base fee (which is the minimum
	// free transaction relay fee).  minTxRelayFee is in Satoshi/KB, so
	// divide the transaction size by 1000 to convert to kilobytes.  Also,
	// integer division is used so fees only increase on full kilobyte
	// boundaries.
	minFee := (1 + serializedLen/1000) * minTxRelayFee

	// Set the minimum fee to the maximum possible value if the calculated
	// fee is not in the valid range for monetary amounts.
	if minFee < 0 || minFee > btcutil.MaxSatoshi {
		minFee = btcutil.MaxSatoshi
	}

	return minFee
}
示例#2
0
// checkSerializedHeight checks if the signature script in the passed
// transaction starts with the serialized block height of wantHeight.
func checkSerializedHeight(coinbaseTx *btcutil.Tx, wantHeight int64) error {
	sigScript := coinbaseTx.MsgTx().TxIn[0].SignatureScript
	if len(sigScript) < 1 {
		str := "the coinbase signature script for blocks of " +
			"version %d or greater must start with the " +
			"length of the serialized block height"
		str = fmt.Sprintf(str, serializedHeightVersion)
		return RuleError(str)
	}

	serializedLen := int(sigScript[0])
	if len(sigScript[1:]) < serializedLen {
		str := "the coinbase signature script for blocks of " +
			"version %d or greater must start with the " +
			"serialized block height"
		str = fmt.Sprintf(str, serializedLen)
		return RuleError(str)
	}

	serializedHeightBytes := make([]byte, 8, 8)
	copy(serializedHeightBytes, sigScript[1:serializedLen+1])
	serializedHeight := binary.LittleEndian.Uint64(serializedHeightBytes)
	if int64(serializedHeight) != wantHeight {
		str := fmt.Sprintf("the coinbase signature script serialized "+
			"block height is %d when %d was expected",
			serializedHeight, wantHeight)
		return RuleError(str)
	}

	return nil
}
示例#3
0
func (c *blockTxCollection) txRecordForInserts(tx *btcutil.Tx) *txRecord {
	if i, ok := c.txIndexes[tx.Index()]; ok {
		return c.txs[i]
	}
	record := &txRecord{tx: tx}

	// If this new transaction record cannot be appended to the end of the
	// txs slice (which would disobey ordering transactions by their block
	// index), reslice and update the block's map of block indexes to txs
	// slice indexes.
	if len(c.txs) > 0 && c.txs[len(c.txs)-1].Tx().Index() > tx.Index() {
		i := uint32(len(c.txs))
		for i != 0 && c.txs[i-1].Tx().Index() >= tx.Index() {
			i--
		}
		detached := c.txs[i:]
		c.txs = append(c.txs[:i], record)
		c.txIndexes[tx.Index()] = i
		for i, r := range detached {
			newIndex := uint32(i + len(c.txs))
			c.txIndexes[r.Tx().Index()] = newIndex
			if _, ok := c.unspent[r.Tx().Index()]; ok {
				c.unspent[r.Tx().Index()] = newIndex
			}
		}
		c.txs = append(c.txs, detached...)
	} else {
		c.txIndexes[tx.Index()] = uint32(len(c.txs))
		c.txs = append(c.txs, record)
	}
	return record
}
示例#4
0
// ValidateTransactionScripts validates the scripts for the passed transaction
// using multiple goroutines.
func ValidateTransactionScripts(tx *btcutil.Tx, txStore TxStore, flags btcscript.ScriptFlags) error {
	// Collect all of the transaction inputs and required information for
	// validation.
	txIns := tx.MsgTx().TxIn
	txValItems := make([]*txValidateItem, 0, len(txIns))
	for txInIdx, txIn := range txIns {
		// Skip coinbases.
		if txIn.PreviousOutpoint.Index == math.MaxUint32 {
			continue
		}

		txVI := &txValidateItem{
			txInIndex: txInIdx,
			txIn:      txIn,
			tx:        tx,
		}
		txValItems = append(txValItems, txVI)
	}

	// Validate all of the inputs.
	validator := newTxValidator(txStore, flags)
	if err := validator.Validate(txValItems); err != nil {
		return err
	}

	return nil

}
示例#5
0
// calcPriority returns a transaction priority given a transaction and the sum
// of each of its input values multiplied by their age (# of confirmations).
// Thus, the final formula for the priority is:
// sum(inputValue * inputAge) / adjustedTxSize
func calcPriority(tx *btcutil.Tx, serializedTxSize int, inputValueAge float64) float64 {
	// In order to encourage spending multiple old unspent transaction
	// outputs thereby reducing the total set, don't count the constant
	// overhead for each input as well as enough bytes of the signature
	// script to cover a pay-to-script-hash redemption with a compressed
	// pubkey.  This makes additional inputs free by boosting the priority
	// of the transaction accordingly.  No more incentive is given to avoid
	// encouraging gaming future transactions through the use of junk
	// outputs.  This is the same logic used in the reference
	// implementation.
	//
	// The constant overhead for a txin is 41 bytes since the previous
	// outpoint is 36 bytes + 4 bytes for the sequence + 1 byte the
	// signature script length.
	//
	// A compressed pubkey pay-to-script-hash redemption with a maximum len
	// signature is of the form:
	// [OP_DATA_73 <73-byte sig> + OP_DATA_35 + {OP_DATA_33
	// <33 byte compresed pubkey> + OP_CHECKSIG}]
	//
	// Thus 1 + 73 + 1 + 1 + 33 + 1 = 110
	overhead := 0
	for _, txIn := range tx.MsgTx().TxIn {
		// Max inputs + size can't possibly overflow here.
		overhead += 41 + minInt(110, len(txIn.SignatureScript))
	}

	if overhead >= serializedTxSize {
		return 0.0
	}

	return inputValueAge / float64(serializedTxSize-overhead)
}
示例#6
0
// IsFinalizedTransaction determines whether or not a transaction is finalized.
func IsFinalizedTransaction(tx *btcutil.Tx, blockHeight int64, blockTime time.Time) bool {
	msgTx := tx.MsgTx()

	// Lock time of zero means the transaction is finalized.
	lockTime := msgTx.LockTime
	if lockTime == 0 {
		return true
	}

	// The lock time field of a transaction is either a block height at
	// which the transaction is finalized or a timestamp depending on if the
	// value is before the lockTimeThreshold.  When it is under the
	// threshold it is a block height.
	blockTimeOrHeight := int64(0)
	if lockTime < lockTimeThreshold {
		blockTimeOrHeight = blockHeight
	} else {
		blockTimeOrHeight = blockTime.Unix()
	}
	if int64(lockTime) < blockTimeOrHeight {
		return true
	}

	// At this point, the transaction's lock time hasn't occured yet, but
	// the transaction might still be finalized if the sequence number
	// for all transaction inputs is maxed out.
	for _, txIn := range msgTx.TxIn {
		if txIn.Sequence != math.MaxUint32 {
			return false
		}
	}
	return true
}
示例#7
0
// newBlockNotifyCheckTxIn is a helper function to iterate through
// each transaction input of a new block and perform any checks and
// notify listening frontends when necessary.
func (s *rpcServer) newBlockNotifyCheckTxIn(tx *btcutil.Tx) {
	for wltNtfn, cxt := range s.ws.requests.m {
		for _, txin := range tx.MsgTx().TxIn {
			for op, id := range cxt.spentRequests {
				if txin.PreviousOutpoint != op {
					continue
				}

				reply := &btcjson.Reply{
					Result: struct {
						TxHash string `json:"txhash"`
						Index  uint32 `json:"index"`
					}{
						TxHash: op.Hash.String(),
						Index:  uint32(op.Index),
					},
					Error: nil,
					Id:    &id,
				}
				replyBytes, err := json.Marshal(reply)
				if err != nil {
					log.Errorf("RPCS: Unable to marshal spent notification: %v", err)
					continue
				}
				wltNtfn <- replyBytes
				s.ws.requests.RemoveSpentRequest(wltNtfn, &op)
			}
		}
	}
}
示例#8
0
文件: tx.go 项目: kingpro/btcwallet
func (u *unconfirmedStore) findDoubleSpend(tx *btcutil.Tx) *txRecord {
	for _, input := range tx.MsgTx().TxIn {
		if r, ok := u.previousOutpoints[input.PreviousOutpoint]; ok {
			return r
		}
	}
	return nil
}
示例#9
0
文件: tx.go 项目: kingpro/btcwallet
// findPreviousCredits searches for all unspent credits that make up the inputs
// for tx.
func (s *Store) findPreviousCredits(tx *btcutil.Tx) ([]Credit, error) {
	type createdCredit struct {
		credit Credit
		err    error
	}

	inputs := tx.MsgTx().TxIn
	creditChans := make([]chan createdCredit, len(inputs))
	for i, txIn := range inputs {
		creditChans[i] = make(chan createdCredit)
		go func(i int, op btcwire.OutPoint) {
			key, ok := s.unspent[op]
			if !ok {
				// Does this input spend an unconfirmed output?
				r, ok := s.unconfirmed.txs[op.Hash]
				switch {
				// Not an unconfirmed tx.
				case !ok:
					fallthrough
				// Output isn't a credit.
				case len(r.credits) <= int(op.Index):
					fallthrough
				// Output isn't a credit.
				case r.credits[op.Index] == nil:
					fallthrough
				// Credit already spent.
				case s.unconfirmed.spentUnconfirmed[op] != nil:
					close(creditChans[i])
					return
				}
				t := &TxRecord{BlockTxKey{BlockHeight: -1}, r, s}
				c := Credit{t, op.Index}
				creditChans[i] <- createdCredit{credit: c}
				return
			}
			r, err := s.lookupBlockTx(key)
			if err != nil {
				creditChans[i] <- createdCredit{err: err}
				return
			}
			t := &TxRecord{key, r, s}
			c := Credit{t, op.Index}
			creditChans[i] <- createdCredit{credit: c}
		}(i, txIn.PreviousOutpoint)
	}
	spent := make([]Credit, 0, len(inputs))
	for _, c := range creditChans {
		cc, ok := <-c
		if !ok {
			continue
		}
		if cc.err != nil {
			return nil, cc.err
		}
		spent = append(spent, cc.credit)
	}
	return spent, nil
}
示例#10
0
// newBlockNotifyCheckTxOut is a helper function to iterate through
// each transaction output of a new block and perform any checks and
// notify listening frontends when necessary.
func (s *rpcServer) newBlockNotifyCheckTxOut(block *btcutil.Block, tx *btcutil.Tx, spent []bool) {
	for wltNtfn, cxt := range s.ws.requests.m {
		for i, txout := range tx.MsgTx().TxOut {
			_, txaddrhash, err := btcscript.ScriptToAddrHash(txout.PkScript)
			if err != nil {
				log.Debug("Error getting payment address from tx; dropping any Tx notifications.")
				break
			}
			for addr, id := range cxt.txRequests {
				if !bytes.Equal(addr[:], txaddrhash) {
					continue
				}
				blkhash, err := block.Sha()
				if err != nil {
					log.Error("Error getting block sha; dropping Tx notification.")
					break
				}
				txaddr, err := btcutil.EncodeAddress(txaddrhash, s.server.btcnet)
				if err != nil {
					log.Error("Error encoding address; dropping Tx notification.")
					break
				}
				reply := &btcjson.Reply{
					Result: struct {
						Sender    string `json:"sender"`
						Receiver  string `json:"receiver"`
						BlockHash string `json:"blockhash"`
						Height    int64  `json:"height"`
						TxHash    string `json:"txhash"`
						Index     uint32 `json:"index"`
						Amount    int64  `json:"amount"`
						PkScript  string `json:"pkscript"`
						Spent     bool   `json:"spent"`
					}{
						Sender:    "Unknown", // TODO(jrick)
						Receiver:  txaddr,
						BlockHash: blkhash.String(),
						Height:    block.Height(),
						TxHash:    tx.Sha().String(),
						Index:     uint32(i),
						Amount:    txout.Value,
						PkScript:  btcutil.Base58Encode(txout.PkScript),
						Spent:     spent[i],
					},
					Error: nil,
					Id:    &id,
				}
				replyBytes, err := json.Marshal(reply)
				if err != nil {
					log.Errorf("RPCS: Unable to marshal tx notification: %v", err)
					continue
				}
				wltNtfn <- replyBytes
			}
		}
	}
}
示例#11
0
func (r *txRecord) setDebitsSpends(spends []*BlockOutputKey, tx *btcutil.Tx) error {
	if r.debits.spends != nil {
		if *r.tx.Sha() == *tx.Sha() {
			return ErrDuplicateInsert
		}
		return ErrInconsistentStore
	}
	r.debits.spends = spends
	return nil
}
示例#12
0
func (u *unconfirmedStore) txRecordForInserts(tx *btcutil.Tx) *txRecord {
	r, ok := u.txs[*tx.Sha()]
	if !ok {
		r = &txRecord{tx: tx}
		u.txs[*tx.Sha()] = r
		for _, input := range r.Tx().MsgTx().TxIn {
			u.previousOutpoints[input.PreviousOutpoint] = r
		}
	}
	return r
}
示例#13
0
// logSkippedDeps logs any dependencies which are also skipped as a result of
// skipping a transaction while generating a block template at the trace level.
func logSkippedDeps(tx *btcutil.Tx, deps *list.List) {
	if deps == nil {
		return
	}

	for e := deps.Front(); e != nil; e = e.Next() {
		item := e.Value.(*txPrioItem)
		minrLog.Tracef("Skipping tx %s since it depends on %s\n",
			item.tx.Sha(), tx.Sha())
	}
}
示例#14
0
文件: mempool.go 项目: kingpro/btcd
// checkPoolDoubleSpend checks whether or not the passed transaction is
// attempting to spend coins already spent by other transactions in the pool.
// Note it does not check for double spends against transactions already in the
// main chain.
//
// This function MUST be called with the mempool lock held (for reads).
func (mp *txMemPool) checkPoolDoubleSpend(tx *btcutil.Tx) error {
	for _, txIn := range tx.MsgTx().TxIn {
		if txR, exists := mp.outpoints[txIn.PreviousOutpoint]; exists {
			str := fmt.Sprintf("transaction %v in the pool "+
				"already spends the same coins", txR.Sha())
			return TxRuleError(str)
		}
	}

	return nil
}
示例#15
0
// Bitcoin specific type checking
func isClassA(tx *btcutil.Tx) bool {
	mtx := tx.MsgTx()
	for _, txOut := range mtx.TxOut {
		_, scriptType := mscutil.GetAddrs(txOut.PkScript)
		if scriptType == btcscript.MultiSigTy {
			return false
		}
	}

	// If it wasn't multi sig it's class a
	return true
}
示例#16
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
}
示例#17
0
// isNonstandardTransaction determines whether a transaction contains any
// scripts which are not one of the standard types.
func isNonstandardTransaction(tx *btcutil.Tx) bool {
	// TODO(davec): Should there be checks for the input signature scripts?

	// Check all of the output public key scripts for non-standard scripts.
	for _, txOut := range tx.MsgTx().TxOut {
		scriptClass := btcscript.GetScriptClass(txOut.PkScript)
		if scriptClass == btcscript.NonStandardTy {
			return true
		}
	}
	return false
}
示例#18
0
文件: mempool.go 项目: kingpro/btcd
// RemoveDoubleSpends removes all transactions which spend outputs spent by the
// passed transaction from the memory pool.  Removing those transactions then
// leads to removing all transactions which rely on them, recursively.  This is
// necessary when a block is connected to the main chain because the block may
// contain transactions which were previously unknown to the memory pool
//
// This function is safe for concurrent access.
func (mp *txMemPool) RemoveDoubleSpends(tx *btcutil.Tx) {
	// Protect concurrent access.
	mp.Lock()
	defer mp.Unlock()

	for _, txIn := range tx.MsgTx().TxIn {
		if txRedeemer, ok := mp.outpoints[txIn.PreviousOutpoint]; ok {
			if !txRedeemer.Sha().IsEqual(tx.Sha()) {
				mp.removeTransaction(txRedeemer)
			}
		}
	}
}
示例#19
0
文件: mempool.go 项目: Cryptoper/btcd
// addTransaction adds the passed transaction to the memory pool.  It should
// not be called directly as it doesn't perform any validation.  This is a
// helper for maybeAcceptTransaction.
//
// This function MUST be called with the mempool lock held (for writes).
func (mp *txMemPool) addTransaction(tx *btcutil.Tx, height, fee int64) {
	// Add the transaction to the pool and mark the referenced outpoints
	// as spent by the pool.
	mp.pool[*tx.Sha()] = &TxDesc{
		Tx:     tx,
		Added:  time.Now(),
		Height: height,
		Fee:    fee,
	}
	for _, txIn := range tx.MsgTx().TxIn {
		mp.outpoints[txIn.PreviousOutpoint] = tx
	}
}
示例#20
0
func (r *txRecord) setCredit(c *credit, index uint32, tx *btcutil.Tx) error {
	if len(r.credits) <= int(index) {
		r.credits = extendCredits(r.credits, index)
	}
	if r.credits[index] != nil {
		if *r.tx.Sha() == *tx.Sha() {
			return ErrDuplicateInsert
		}
		return ErrInconsistentStore
	}

	r.credits[index] = c
	return nil
}
示例#21
0
// newBlockNotifyCheckTxIn is a helper function to iterate through
// each transaction input of a new block and perform any checks and
// notify listening frontends when necessary.
func (s *rpcServer) newBlockNotifyCheckTxIn(tx *btcutil.Tx) {
	for _, txin := range tx.MsgTx().TxIn {
		if clist, ok := s.ws.spentNotifications[txin.PreviousOutpoint]; ok {
			var enext *list.Element
			for e := clist.Front(); e != nil; e = enext {
				enext = e.Next()
				c := e.Value.(walletChan)
				notifySpentData(c, &txin.PreviousOutpoint.Hash,
					txin.PreviousOutpoint.Index, tx)
				s.ws.RemoveSpentRequest(c, &txin.PreviousOutpoint)
			}
		}
	}
}
示例#22
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
}
示例#23
0
// findPreviousCredits searches for all unspent credits that make up the inputs
// for tx.  This lookup is very expensive and should be avoided at all costs.
func (s *Store) findPreviousCredits(tx *btcutil.Tx) ([]*Credit, error) {
	unfound := make(map[btcwire.OutPoint]struct{}, len(tx.MsgTx().TxIn))
	for _, txIn := range tx.MsgTx().TxIn {
		unfound[txIn.PreviousOutpoint] = struct{}{}
	}

	spent := make([]*Credit, 0, len(unfound))

done:
	for blockHeight := range s.unspent {
		b, err := s.lookupBlock(blockHeight)
		if err != nil {
			return nil, err
		}

		for blockIndex, txIdx := range b.unspent {
			if uint32(len(b.txs)) <= txIdx {
				return nil, MissingBlockTxError{
					BlockIndex:  blockIndex,
					BlockHeight: blockHeight,
				}
			}
			r := b.txs[txIdx]

			op := btcwire.OutPoint{Hash: *r.Tx().Sha()}
			for i, cred := range r.credits {
				if cred == nil || cred.spentBy != nil {
					continue
				}

				op.Index = uint32(i)
				if _, ok := unfound[op]; ok {
					key := BlockTxKey{blockIndex, b.Height}
					t := &TxRecord{key, r, s}
					c := &Credit{t, op.Index}
					spent = append(spent, c)

					delete(unfound, op)
					if len(unfound) == 0 {
						break done
					}
				}
			}
		}
	}

	return spent, nil
}
示例#24
0
文件: filter.go 项目: kac-/btcutil
// matchTxAndUpdate returns true if the bloom filter matches data within the
// passed transaction, otherwise false is returned.  If the filter does match
// the passed transaction, it will also update the filter depending on the bloom
// update flags set via the loaded filter if needed.
//
// This function MUST be called with the filter lock held.
func (bf *Filter) matchTxAndUpdate(tx *btcutil.Tx) bool {
	// Check if the filter matches the hash of the transaction.
	// This is useful for finding transactions when they appear in a block.
	matched := bf.matches(tx.Sha().Bytes())

	// Check if the filter matches any data elements in the public key
	// scripts of any of the outputs.  When it does, add the outpoint that
	// matched so transactions which spend from the matched transaction are
	// also included in the filter.  This removes the burden of updating the
	// filter for this scenario from the client.  It is also more efficient
	// on the network since it avoids the need for another filteradd message
	// from the client and avoids some potential races that could otherwise
	// occur.
	for i, txOut := range tx.MsgTx().TxOut {
		pushedData, err := btcscript.PushedData(txOut.PkScript)
		if err != nil {
			continue
		}

		for _, data := range pushedData {
			if !bf.matches(data) {
				continue
			}

			matched = true
			bf.maybeAddOutpoint(txOut.PkScript, tx.Sha(), uint32(i))
			break
		}
	}

	// Nothing more to do if a match has already been made.
	if matched {
		return true
	}

	// At this point, the transaction and none of the data elements in the
	// public key scripts of its outputs matched.

	// Check if the filter matches any outpoints this transaction spends or
	// any any data elements in the signature scripts of any of the inputs.
	for _, txin := range tx.MsgTx().TxIn {
		if bf.matchesOutPoint(&txin.PreviousOutpoint) {
			return true
		}

		pushedData, err := btcscript.PushedData(txin.SignatureScript)
		if err != nil {
			continue
		}
		for _, data := range pushedData {
			if bf.matches(data) {
				return true
			}
		}
	}

	return false
}
示例#25
0
文件: tx.go 项目: kingpro/btcwallet
func (r *txRecord) setCredit(index uint32, change bool, tx *btcutil.Tx) error {
	if r.credits == nil {
		r.credits = make([]*credit, 0, len(tx.MsgTx().TxOut))
	}
	for i := uint32(len(r.credits)); i <= index; i++ {
		r.credits = append(r.credits, nil)
	}
	if r.credits[index] != nil {
		if *r.tx.Sha() == *tx.Sha() {
			return ErrDuplicateInsert
		}
		return ErrInconsistentStore
	}
	r.credits[index] = &credit{change: change}
	return nil
}
示例#26
0
// Helper function
func GetAddrsClassA(tx *btcutil.Tx) []Output {
	var addrs []Output

	mtx := tx.MsgTx()
	for _, txOut := range mtx.TxOut {
		a, _ := GetAddrs(txOut.PkScript)

		// There are some bogus transactions out there that don't generate a valid address, skip these outputs
		if len(a) > 0 {
			out := Output{Value: txOut.Value, Addr: a[0].Addr}

			addrs = append(addrs, out) // a is one address guaranteed
		}
	}

	return addrs
}
示例#27
0
// IsCoinBase determines whether or not a transaction is a coinbase.  A coinbase
// is a special transaction created by miners that has no inputs.  This is
// represented in the block chain by a transaction with a single input that has
// a previous output transaction index set to the maximum value along with a
// zero hash.
func IsCoinBase(tx *btcutil.Tx) bool {
	msgTx := tx.MsgTx()

	// A coin base must only have one transaction input.
	if len(msgTx.TxIn) != 1 {
		return false
	}

	// The previous output of a coin base must have a max value index and
	// a zero hash.
	prevOut := msgTx.TxIn[0].PreviousOutpoint
	if prevOut.Index != math.MaxUint32 || !prevOut.Hash.IsEqual(zeroHash) {
		return false
	}

	return true
}
示例#28
0
// FetchTransactionStore fetches the input transactions referenced by the
// passed transaction from the point of view of the end of the main chain.  It
// also attempts to fetch the transaction itself so the returned TxStore can be
// examined for duplicate transactions.
func (b *BlockChain) FetchTransactionStore(tx *btcutil.Tx) (TxStore, error) {
	// Create a set of needed transactions from the transactions referenced
	// by the inputs of the passed transaction.  Also, add the passed
	// transaction itself as a way for the caller to detect duplicates.
	txNeededSet := make(map[btcwire.ShaHash]struct{})
	txNeededSet[*tx.Sha()] = struct{}{}
	for _, txIn := range tx.MsgTx().TxIn {
		txNeededSet[txIn.PreviousOutPoint.Hash] = struct{}{}
	}

	// Request the input transactions from the point of view of the end of
	// the main chain without including fully spent trasactions in the
	// results.  Fully spent transactions are only needed for chain
	// reorganization which does not apply here.
	txStore := fetchTxStoreMain(b.db, txNeededSet, false)
	return txStore, nil
}
示例#29
0
// checkInputsStandard performs a series of checks on a transaction's inputs
// to ensure they are "standard".  A standard transaction input is one that
// that consumes the expected number of elements from the stack and that number
// is the same as the output script pushes.  This help prevent resource
// exhaustion attacks by "creative" use of scripts that are super expensive to
// process like OP_DUP OP_CHECKSIG OP_DROP repeated a large number of times
// followed by a final OP_TRUE.
func checkInputsStandard(tx *btcutil.Tx, txStore btcchain.TxStore) error {
	// NOTE: The reference implementation also does a coinbase check here,
	// but coinbases have already been rejected prior to calling this
	// function so no need to recheck.

	for i, txIn := range tx.MsgTx().TxIn {
		// It is safe to elide existence and index checks here since
		// they have already been checked prior to calling this
		// function.
		prevOut := txIn.PreviousOutpoint
		originTx := txStore[prevOut.Hash].Tx.MsgTx()
		originPkScript := originTx.TxOut[prevOut.Index].PkScript

		// Calculate stats for the script pair.
		scriptInfo, err := btcscript.CalcScriptInfo(txIn.SignatureScript,
			originPkScript, true)
		if err != nil {
			str := fmt.Sprintf("transaction input #%d script parse "+
				"failure: %v", i, err)
			return txRuleError(btcwire.RejectNonstandard, str)
		}

		// A negative value for expected inputs indicates the script is
		// non-standard in some way.
		if scriptInfo.ExpectedInputs < 0 {
			str := fmt.Sprintf("transaction input #%d expects %d "+
				"inputs", i, scriptInfo.ExpectedInputs)
			return txRuleError(btcwire.RejectNonstandard, str)
		}

		// The script pair is non-standard if the number of available
		// inputs does not match the number of expected inputs.
		if scriptInfo.NumInputs != scriptInfo.ExpectedInputs {
			str := fmt.Sprintf("transaction input #%d expects %d "+
				"inputs, but referenced output script provides "+
				"%d", i, scriptInfo.ExpectedInputs,
				scriptInfo.NumInputs)
			return txRuleError(btcwire.RejectNonstandard, str)
		}
	}

	return nil
}
示例#30
0
文件: mempool.go 项目: Cryptoper/btcd
// removeTransaction is the internal function which implements the public
// RemoveTransaction.  See the comment for RemoveTransaction for more details.
//
// This function MUST be called with the mempool lock held (for writes).
func (mp *txMemPool) removeTransaction(tx *btcutil.Tx) {
	// Remove any transactions which rely on this one.
	txHash := tx.Sha()
	for i := uint32(0); i < uint32(len(tx.MsgTx().TxOut)); i++ {
		outpoint := btcwire.NewOutPoint(txHash, i)
		if txRedeemer, exists := mp.outpoints[*outpoint]; exists {
			mp.removeTransaction(txRedeemer)
		}
	}

	// Remove the transaction and mark the referenced outpoints as unspent
	// by the pool.
	if txDesc, exists := mp.pool[*txHash]; exists {
		for _, txIn := range txDesc.Tx.MsgTx().TxIn {
			delete(mp.outpoints, txIn.PreviousOutpoint)
		}
		delete(mp.pool, *txHash)
	}
}