Published: 2018-12-11

BIP34(Block v2, Height in Coinbase)

1 BIP地址

BIP34

BIP: 34
Layer: Consensus (soft fork)
Title: Block v2, Height in Coinbase
Author: Gavin Andresen <gavinandresen@gmail.com>
Comments-Summary: No comments yet.
Comments-URI: https://github.com/bitcoin/bips/wiki/Comments:BIP-0034
Status: Final
Type: Standards Track
Created: 2012-07-06

2 原因和目的

BIP34提出和实践了一种升级机制,使得网络上的参与者可以就交易或者区块的结构、规则和行为变更达成共识。 另外还通过在coinbase里包含区块高度,保证了交易和区块的唯一性,来帮助区块验证。

3 细节

  1. 将version大于1的交易视为"non-standard"
  2. 将区块高度以"serialized CScript"的格式添加到coinbase交易的scriptSig中,block version提高到2
  3. 75%原则:如果过去1000个区块都有750个区块的block version比2大,那么拒绝无效的version=2的Block
  4. 95%原则:如果过去1000个区块都有950个区块的block version比2大,那么拒绝version=1的区块

4 相关实现

判断一个block是否应该在coinbase包含区块高度

// serializedHeightVersion is the block version which changed block
// coinbases to start with the serialized block height.
serializedHeightVersion = 2

// ShouldHaveSerializedBlockHeight determines if a block should have a
// serialized block height embedded within the scriptSig of its
// coinbase transaction. Judgement is based on the block version in the block
// header. Blocks with version 2 and above satisfy this criteria. See BIP0034
// for further information.
func ShouldHaveSerializedBlockHeight(header *wire.BlockHeader) bool {
        return header.Version >= serializedHeightVersion
}

提取出coinbase中的区块高度

// ExtractCoinbaseHeight attempts to extract the height of the block from the
// scriptSig of a coinbase transaction.  Coinbase heights are only present in
// blocks of version 2 or later.  This was added as part of BIP0034.
func ExtractCoinbaseHeight(coinbaseTx *btcutil.Tx) (int32, 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 0, ruleError(ErrMissingCoinbaseHeight, str)
        }

        // Detect the case when the block height is a small integer encoded with
        // as single byte.
        opcode := int(sigScript[0])
        if opcode == txscript.OP_0 {
                return 0, nil
        }
        if opcode >= txscript.OP_1 && opcode <= txscript.OP_16 {
                return int32(opcode - (txscript.OP_1 - 1)), nil
        }

        // Otherwise, the opcode is the length of the following bytes which
        // encode in the block height.
        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 0, ruleError(ErrMissingCoinbaseHeight, str)
        }

        serializedHeightBytes := make([]byte, 8)
        copy(serializedHeightBytes, sigScript[1:serializedLen+1])
        serializedHeight := binary.LittleEndian.Uint64(serializedHeightBytes)

        return int32(serializedHeight), nil
}

5 END

Author: Nisen

Email: imnisen@163.com