1

BIP30(duplicate transactions)

 2 years ago
source link: https://imnisen.github.io/bip0030.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

BIP30(duplicate transactions)

1 BIP地址

BIP30

BIP: 30
Layer: Consensus (soft fork)
Title: Duplicate transactions
Author: Pieter Wuille <[email protected]>
Comments-Summary: No comments yet.
Comments-URI: https://github.com/bitcoin/bips/wiki/Comments:BIP-0030
Status: Final
Type: Standards Track
Created: 2012-02-22
License: BSD-2-Clause

2 原因和目的

Bitcoin参考实现默认重复交易(txid相同)不存在,但这是不对的,特别是coinbase tx很容易去重复。针对重复交易可以发起一些攻击来时的完全确认但交易回滚,从而导致双花等问题。

BIP30提出了一个处理重复交易的方案。

规则是: 不允许包含与未完全花费的交易id相同id的交易到区块链。

Mainnet从March 15, 2012, 00:00 UTC (testnet: February 20, 2012 00:00 UTC)开始应用,除去两个历史的例外block(blocks at heights 91842 and 91880)

4 相关实现

参考btcd的实现

检查是不是例外的block

// isBIP0030Node returns whether or not the passed node represents one of the
// two blocks that violate the BIP0030 rule which prevents transactions from
// overwriting old ones.
func isBIP0030Node(node *blockNode) bool {
        if node.height == 91842 && node.hash.IsEqual(block91842Hash) {
                return true
        }

        if node.height == 91880 && node.hash.IsEqual(block91880Hash) {
                return true
        }

        return false

检查是否和未花费的utxo相同id

// checkBIP0030 ensures blocks do not contain duplicate transactions which
// 'overwrite' older transactions that are not fully spent.  This prevents an
// attack where a coinbase and all of its dependent transactions could be
// duplicated to effectively revert the overwritten transactions to a single
// confirmation thereby making them vulnerable to a double spend.
//
// For more details, see
// https://github.com/bitcoin/bips/blob/master/bip-0030.mediawiki and
// http://r6.ca/blog/20120206T005236Z.html.
//
// This function MUST be called with the chain state lock held (for reads).
func (b *BlockChain) checkBIP0030(node *blockNode, block *btcutil.Block, view *UtxoViewpoint) error {
        // Fetch utxos for all of the transaction ouputs in this block.
        // Typically, there will not be any utxos for any of the outputs.
        fetchSet := make(map[wire.OutPoint]struct{})
        for _, tx := range block.Transactions() {
                prevOut := wire.OutPoint{Hash: *tx.Hash()}
                for txOutIdx := range tx.MsgTx().TxOut {
                        prevOut.Index = uint32(txOutIdx)
                        fetchSet[prevOut] = struct{}{}
                }
        }
        err := view.fetchUtxos(b.db, fetchSet)
        if err != nil {
                return err
        }

        // Duplicate transactions are only allowed if the previous transaction
        // is fully spent.
        for outpoint := range fetchSet {
                utxo := view.LookupEntry(outpoint)
                if utxo != nil && !utxo.IsSpent() {
                        str := fmt.Sprintf("tried to overwrite transaction %v "+
                                "at block height %d that is not fully spent",
                                outpoint.Hash, utxo.BlockHeight())
                        return ruleError(ErrOverwriteTx, str)
                }
        }

        return nil
}

检查区块有效性的方法,核心是调用上面两个方法

func (b *BlockChain) checkConnectBlock(node *blockNode, block *btcutil.Block, view *UtxoViewpoint, stxos *[]SpentTxOut) error {
        /* 省略其它 */

        // BIP0030 added a rule to prevent blocks which contain duplicate
        // transactions that 'overwrite' older transactions which are not fully
        // spent.  See the documentation for checkBIP0030 for more details.
        //
        // There are two blocks in the chain which violate this rule, so the
        // check must be skipped for those blocks.  The isBIP0030Node function
        // is used to determine if this block is one of the two blocks that must
        // be skipped.
        //
        // In addition, as of BIP0034, duplicate coinbases are no longer
        // possible due to its requirement for including the block height in the
        // coinbase and thus it is no longer possible to create transactions
        // that 'overwrite' older ones.  Therefore, only enforce the rule if
        // BIP0034 is not yet active.  This is a useful optimization because the
        // BIP0030 check is expensive since it involves a ton of cache misses in
        // the utxoset.
        if !isBIP0030Node(node) && (node.height < b.chainParams.BIP0034Height) {
                err := b.checkBIP0030(node, block, view)
                if err != nil {
                        return err
                }
        }

        /* 省略其它 */
}


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK