Constructure
Block
保存所有的交易,交易计算出的默克尔根,指向前一个区块的哈希指针,时间戳,随机数nonce,本区块的哈希。
longnoncelongtimestampStringpreviousBlockHashintdifficultyBits
nbits编码List<Transaction>transactionTransactioncoinbaseTransaction
独立字段,方便快速校验 subsidyStringmerkleRootStringhash
Hex 工具类统一 64 位定长
getMerkleRoot()计算默克尔根,工具方法,递归 double-sha256,叶子顺序 txId。computeBlockHash()计算区块哈希,固定顺序:version + prevHash + merkleRoot + time + bits + nonce → double-sha256 → 小端 hex。validateBlockHeader()- 难度校验:hash ≤ targetFromBits(difficultyBits)
- 时间漂移:time ≤ now+7200s(Bitcoin 规则)
- coinbase 必须在`tx[0]且仅有一个。
Transaction
交易,采用utxo模型,没有账户概念。
Stringversion
目前固定为1longtimestampStringtxIdList<TxIn>txInsList<TxOut>txOuts
calculateTxId()计算交易哈希(即txId)
把 version|timestamp|txIns[]|txOuts[] 序列化后 double-sha256。注意txIns的签名不参与计算。getSizeBytes()预估交易体积
TxIn
交易输入。
StringprevTxIdintprevTxOutIndexStringsignature
Hex 编码的 DER 签名StringpubKey
Hex 编码的压缩公钥(33 字节)
-
签名内容 = 简化后的“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。 -
验签
在 Blockchain.addTransaction() 时执行:
ECDSA.verify(toSign, signature, pubKey)
TxOut
StringrecipientPubKeyHash
Hex,20 字节 RIPEMD160(SHA256(pubKey))longamount
单位是聪
- 解锁条件简化规则
花费时必须提供:- 与 recipientPubKeyHash 匹配的公钥(33 字节)
- 对该笔交易整体哈希的有效 ECDSA 签名
即“谁掌握私钥,谁就能花”。
- serialize()/deserialize()
用于持久化与网络传输,顺序:amount(8)+recipientPubKeyHash(20) 共 28 字节。
Miner
矿工类,可以有单个wallet,打包交易调用Block生成新区块。
WalletcoinbaseWalletStringextraNonce
可放入 coinbase 脚本,防止快速重复(我也不知道啥意思)
BlockmineBlock(Blockchainchain,List<Transaction>txs)
Wallet
管理密钥对、创建交易、查看余额
ECKeykeyPair 密钥对Stringaddress;
Base58Check(0x00 + hash160 + 4 字节校验)Map<String, TxOut>ownedUtxo;
仅跟踪与己相关的 UTXOlongupdateTime
StringgetAddress()
return Base58Check.encode(Hash160.of(keyPair.getPubKey()));- Transaction createTransaction(
List<TxOut>txOuts) voidsyncWithChain(Blockchain chain)
扫描链上所有区块,把 pubKeyHash 匹配的 TxOut 加入 ownedUtxo,同时删除已花费的。
Blockchain
区块链全节点实例,通过创建一个Blockchain来启动一个全节点。
List<Block>chainintdifficultyBits
每2016块调整ConcurrentLinkedQueue<Transaction>pendingTransactionsBigDecimalminingRewardConcurrentHashMap<String, Transaction.TxOut>utxoPool = new ConcurrentHashMap<>()
- addBlock(Block b)
- 校验 header、merkle、难度、时间、coinbase;
- 每笔交易执行双花检查:txIn使用的UTXO必须存在于utxoPool。
- 更新utxoPool:删除所有输入,新增所有输出
- 加入chain中
- 持久化(先不做)
- createGenesisBlock
- getLatestBlock
- getPendingTransactions
- addTransactionToPending
- 格式、签名、金额、UTXO 存在性校验;
- 加入pendingTransactions。
- minePendingTransactions
- createCoinbaseTransaction
- 分叉处理(先不实现)
Utils
-
HashUtils
– doubleSha256(byte[] data)
– hash160(byte[] pubKey) -
TargetUtils
– decodeBits(int bits) → BigInteger target
– encodeBits(BigInteger target) → int -
ECDSAUtils
– sign(byte[] message, BigInteger priv)
– verify(byte[] message, String sigHex, String pubKeyHex) -
Base58Check
– encode/decoder,带 4 字节校验。