币地址

比特币地址是一个由数字和字母组成的字符串,并且由公钥经过Hash函数生成。通常我们见到的比特币地址是经过Base58Check编码的,这种编码使用了58个字符和校验码,提高了可读性、避免了歧义,并能有效防止地址输入时产生的错误。

Base58编码

base58和base64一样是一种二进制转可视字符串的算法,主要用来转换大整数值。区别是,转换出来的字符串,去除了几个看起来会产生歧义的字符,如 0 (零), O (大写字母O), I (大写的字母i) and l (小写的字母L) ,和几个影响双击选择的字符,如/, +。结果字符集正好58个字符(包括9个数字,24个大写字母,25个小写字母)。

在比特币的实现中,Base58Check编码位于src\base58.cpp中,定义的所有字符如下:

/** All alphanumeric characters except for "0", "I", "O", and "l" */
static const char* pszBase58 = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
  • 1
  • 2

比特币地址生成流程

上图清楚的展示了如何将椭圆曲线(ECC)公钥转换成比特币地址,首先我们知道ECC公钥是指坐标上的一个点(x,y)横纵坐标分别用32字节表示,也就是256位。然后每个步骤最前面的“1”表示1个字节,用来代表不同的网络。最后就是两种哈希函数,sha256ripemd160,我们从它们名称结尾的数字就可以判断它们输出的比特位数,最后通过组合得出最到的比特币地址。

那么一个直接的问题就是,为什么地址生成的流程要这么复杂呢?

个人认为,这种设计是为了防御量子计算机的攻击,为了使比特币系统更加安全。我们知道,如果量子计算机被成功的建造了出来,那么现存的几乎所有的公钥密码系统都将被攻破,无论是基于大整数分解还是离散对数,亦或是椭圆曲线离散对数,都将是不安全的,而不安全的意思就是说能从公钥直接计算出私钥。但是哈希函数却依然是安全的,当然前提是哈希函数具有足够的随机性,只能通过暴力枚举的方式来破解,拿sha256来举例,输出为256位,那么哈希值的结果空间大小为2^256,这个空间大到就算量子计算机也无法在有效的时间内的破解。

在实际应用当中,假如地址A给地址B发送了一笔交易Tx1,那么B就可以通过将自己的公钥和签名写入新交易Tx2中从而将Tx1作为Tx2的输入,此时Tx2中就包括了地址B和B对应的公钥,一旦B将Tx2广播出去,那么所有人都将知道地址B和B对应的公钥,此时攻击者如果利用量子计算机进行攻击,那么此后所有转到地址B的交易攻击者都能进行花费;但是在B暴露自己的公钥之前,也就是没有花费过任何转到地址B的交易,那么即使有量子计算机也无法进行攻击。

通过以上解释,我们可以总结出量子计算机出来之后的比特币安全交易方式:不要重复使用已花费过的比特币地址,那么你的所有交易就是安全的。



在区块链网络当中,所有的数据都以区块的形式记录在各个节点上。而每个区块又以单独的文件保存在节点本地磁盘上,在比特币(Linux系统)中所有的区块信息都保存在~/.bitcoin/blocks/目录下面,并以blk***.dat文件名标示,如下图所示:

blocks

区块结构

根据https://en.bitcoin.it/wiki/Block所描述的,区块的结构如下:

Field描述大小
Magic no”魔法数“,常数0xD9B4BEF94 bytes
Blocksize区块大小4 bytes
Blockheader区块头80 bytes
Transaction counter交易数量,正整数1 - 9 bytes
transactions交易列表-many transactions

首先是一个“魔法数”,根据描述这是个常数占4个字节,然后是4个字节的区块大小,然后是区块头80字节,然后是1-9字节的交易数量,最后是所有的交易。但是在实际的比特币代码当中却并不是这么定义的,

class CBlock : public CBlockHeader
{
public:
    // network and disk
    std::vector<CTransactionRef> vtx;

    // memory only
    mutable bool fChecked;

    // ...

    CBlockHeader GetBlockHeader() const
    {
        CBlockHeader block;
        block.nVersion       = nVersion;
        block.hashPrevBlock  = hashPrevBlock;
        block.hashMerkleRoot = hashMerkleRoot;
        block.nTime          = nTime;
        block.nBits          = nBits;
        block.nNonce         = nNonce;
        return block;
    }

    std::string ToString() const;
};
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25

可以发现,实际上只定义了区块头和所有的交易,或许是不同版本的差异,但是看github上过去版本的bitcoin代码中也都没有定义上述表格中的变量,所以个人认为实际的结构应该是代码中定义的。

再来看看区块头部的结构,https://en.bitcoin.it/wiki/Block_hashing_algorithm

Field目的更新时间大小 (Bytes)
Version区块版本号升级软件并指定新版本号时4
hashPrevBlock前一个区块的256-bit 哈希值产生新的区块32
hashMerkleRootMerkle树根的256-bit 哈希值收到了新的交易32
Time从 1970-01-01 00:00 UTC到现在为止的时间间隔,单位为秒每几秒4
Bits当前POW的目标哈希值的压缩形式难度调整时4
Nonce32-bit 随机数尝试新的hash时4

每个区块头都包含前一个区块的哈希值,所以所有的区块就像链表一样连成了一条链,链的头部就是创世块(Genesis Block)。所有的交易都以Merkle tree的形式进行索引,并在block header中保存Merkle tree的树根,如果当前交易数量是奇数的话,那么最后一个交易将会被计算两次哈希值。当前POW的难度以压缩的形式保存在4个字节的Bits中,最后通过mining找到的随机数记录在最后的Nonce中。

交易结构

关于比特币交易,更好的参考是比特币官方文档https://en.bitcoin.it/wiki/Transaction,解释的很详细。

交易是在区块链网络中传输的最基本的数据结构,所有有效的交易最终都会被打包进区块中并保存在区块链上,比特币中交易的数据结构如下,

Field描述大小
Version no版本号,当前为14 bytes
In-counter输入交易数量,正整数1 - 9 bytes
list of inputs输入列表,每个区块中第一个交易被称为“Coinbase”-many inputs
Out-counter输出交易数量,正整数1 - 9 bytes
list of outputs输出列表,每个区块中第一个输出交易是给矿工的奖励-many outputs
lock_time锁定时间,如果非0并且小于0xFFFFFFFF,那么就是指块序号;如果交易已经终结,那么就是指时间戳4 bytes

一个简单的交易输入如下:

Input:
Previous tx: f5d8ee39a430901c91a5917b9f2dc19d6d1a0e9cea205b009ca73dd04470b9a6
Index: 0
scriptSig: 304502206e21798a42fae0e854281abd38bacd1aeed3ee3738d9e1446618c4571d10
90db022100e2ac980643b0b82c0e88ffdfec6b64e3e6ba35e7ba5fdd7d5d6cc8d25c6b241501
  • 1
  • 2
  • 3
  • 4
  • 5

首先是前一笔交易的哈希值(Previous tx),然后是花费的是第几个输出(Index),最后是解锁脚本(scriptSig),其中解锁脚本=签名+公钥,只有提供正确的解锁脚本,才能花费对应的交易。

一个简单的输出如下:

Output:
Value: 5000000000
scriptPubKey: OP_DUP OP_HASH160 404371705fa9bd789a2fcd52d2c580b65d35549d
OP_EQUALVERIFY OP_CHECKSIG
  • 1
  • 2
  • 3
  • 4

首先是输出金额(Value),然后是锁定脚本,锁定脚本包括脚本系统中的一系列操作符。

交易类型

比特币目前提供了两种不同的交易类型,如下所示。通过这两者类型的交易可以组合出更加复杂的交易,称之为合约。

(1)Pay-to-PubkeyHash

scriptPubKey: OP_DUP OP_HASH160 <pubKeyHash> OP_EQUALVERIFY OP_CHECKSIG
scriptSig: <sig> <pubKey>
  • 1
  • 2

这个也是最常见的交易,目标地址就是比特币地址,花费时需要提供签名和公钥。

(2)Pay-to-Script-Hash(P2SH)

scriptPubKey: OP_HASH160 <scriptHash> OP_EQUAL 
scriptSig: ..signatures... <serialized script>
  • 1
  • 2

在P2SH中,目标地址由脚本哈希取代,解锁脚本中才包含签名和脚本内容。下面有两种类型的交易的对比,首先是普通的多签名脚本,解锁脚本中只需要5个公钥中任意两个私钥的签名即可。

Locking Script2 PubKey1 PubKey2 PubKey3 PubKey4 PubKey5 5 OP_CHECKMULTISIG
Unlocking ScriptSig1 Sig2

然后是P2SH脚本,

Redeem Script2 PubKey1 PubKey2 PubKey3 PubKey4 PubKey5 5 OP_CHECKMULTISIG
Locking ScriptOP_HASH160 <20-byte hash of redeem script> OP_EQUAL
Unlocking ScriptSig1 Sig2 redeem script

可以看出锁定脚本中只需要包括Redeem Script的哈希即可,而不用包含长长的一串公钥信息,具体的脚本内容由解锁脚本提供,相当于是将交易的大部分内容交给了交易花费者去处理,从而减少了网络传输的数据。根据《Master Bitcoin》所述,与直接使⽤复杂脚本以锁定输出的⽅式相⽐,P2SH具有以下特点:

  • 在交易输出中,复杂脚本由简短电⼦指纹取代,使得交易代码变短。
  • 脚本能被编译为地址,⽀付指令的发出者和⽀付者的⽐特币钱包不需要复杂⼯序就可以执⾏P2SH。
  • P2SH将构建脚本的重担转移⾄接收⽅,⽽⾮发送⽅。
  • P2SH将⻓脚本数据存储的负担从输出⽅(存储于UTXO集,影响内存)转移⾄输⼊⽅(仅存储于区块链)。
  • P2SH将⻓脚本数据存储的重担从当前(⽀付时)转移⾄未来(花费时)。
  • P2SH将⻓脚本的交易费成本从发送⽅转移⾄接收⽅,接收⽅在使⽤该笔资⾦时必须含有赎回脚本。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值