Constructure

Block

保存所有的交易,交易计算出的默克尔根,指向前一个区块的哈希指针,时间戳,随机数nonce,本区块的哈希。

  1. getMerkleRoot()计算默克尔根,工具方法,递归 double-sha256,叶子顺序 txId。
  2. computeBlockHash()计算区块哈希,固定顺序:version + prevHash + merkleRoot + time + bits + nonce → double-sha256 → 小端 hex。
  3. validateBlockHeader()
    1. 难度校验:hash ≤ targetFromBits(difficultyBits)
    2. 时间漂移:time ≤ now+7200s(Bitcoin 规则)
    3. coinbase 必须在`tx[0]且仅有一个。

Transaction

交易,采用utxo模型,没有账户概念。

  1. calculateTxId() 计算交易哈希(即txId)
    把 version|timestamp|txIns[]|txOuts[] 序列化后 double-sha256。注意txIns的签名不参与计算。
  2. getSizeBytes()预估交易体积

TxIn

交易输入。

  1. 签名内容 = 简化后的“SIGHASH_ALL”
    byte[] toSign = TxUtils.getRawDataToSign(spendingTx, inputIndex, prevTxOut);
    具体做法:
    a) 把当前交易所有 txIn 的 signature 字段先置空;
    b) 把对应 txIn 的 prevTxOut.script 字段替换成 prevTxOut.amount+pubKey 的简单拼接;
    c) 对整个交易做 double-sha256;
    d) 使用 ECDSA(secp256k1) 签名,结果转 DER → Hex。

  2. 验签
    在 Blockchain.addTransaction() 时执行:
    ECDSA.verify(toSign, signature, pubKey)

TxOut

  1. 解锁条件简化规则
    花费时必须提供:
    • 与 recipientPubKeyHash 匹配的公钥(33 字节)
    • 对该笔交易整体哈希的有效 ECDSA 签名
      即“谁掌握私钥,谁就能花”。
  2. serialize()/deserialize()
    用于持久化与网络传输,顺序:amount(8)+recipientPubKeyHash(20) 共 28 字节。

Miner

矿工类,可以有单个wallet,打包交易调用Block生成新区块。

  1. Block mineBlock(Blockchain chain, List<Transaction> txs)

Wallet

管理密钥对、创建交易、查看余额

  1. String getAddress()
    return Base58Check.encode(Hash160.of(keyPair.getPubKey()));
  2. Transaction createTransaction(List<TxOut> txOuts)
  3. void syncWithChain(Blockchain chain)
    扫描链上所有区块,把 pubKeyHash 匹配的 TxOut 加入 ownedUtxo,同时删除已花费的。

Blockchain

区块链全节点实例,通过创建一个Blockchain来启动一个全节点。

  1. addBlock(Block b)
    1. 校验 header、merkle、难度、时间、coinbase;
    2. 每笔交易执行双花检查:txIn使用的UTXO必须存在于utxoPool。
    3. 更新utxoPool:删除所有输入,新增所有输出
    4. 加入chain中
    5. 持久化(先不做)
  2. createGenesisBlock
  3. getLatestBlock
  4. getPendingTransactions
  5. addTransactionToPending
    1. 格式、签名、金额、UTXO 存在性校验;
    2. 加入pendingTransactions。
  6. minePendingTransactions
  7. createCoinbaseTransaction
  8. 分叉处理(先不实现)

Utils