比特币的地址生成:
生成方式: 由公钥 –》 sha256(公钥) –》 RIPEMD160(上步结果) –》base58check(上步结果) === 比特币地址; 示例: 1J7mdg5rbQyUHENYdx39WVWK7fsLpEoXZy; 长度为34个字节, 该为Base58check编码后的字符串。比特币网络
节点采用TCP协议、使用8333端口.校验交易
打包交易前,校验如何打包交易最合算。打包交易Mempool:
打包交易前的校验算法, 主要数据来源.比特币交易的集中方式:
P2PKH: 此类交易都含有一个锁定脚本,该脚本由公钥哈希实现阻止输出功能.支付给公钥哈希的交易 由P2PKH脚本锁定的输出可以通过键入公钥和由相应私钥创设的数字签名得以解锁。 P2PK: 支付给公钥的交易 主要目的一方面为使比特币地址更简短,另一方面也使之更方便使用。多重签名交易: 支付给多个P2SH: 复杂的锁定脚本被电子指纹所取代,电子指纹为密码学哈希。 1 在现金交易中的锁定脚本是这种: 确保在赎回交易中提供的脚本的哈希,是这个创建地址的脚本的哈希。mempool中的交易:
1 通过检查后的合法交易2 检查的内容: 交易对象合法, 脚本是否合法, 是否放入区块,3 交易本身的验证, 交易链的验证—》 全在已经确认的block里面,4 交易与block的交互: 交易扔给一个交易哈希, block返回一个交易的内容5 检测交易的两种路径: 检查已确认的区块, 检查mempool。6 优化方案:交易数据长度问题:
1 交易数据长度分为4个等级: 1 交易数据长度 < 253 byte; 使用1个字节表示交易长度。该字节直接表示接下来交易的数据长度,它后面紧跟交易数据;(即:在标识交易长度方面,使用了1个字节,该字节直接表示交易的长度)2 交易数据长度 < 65535 byte; 使用一个字节 0xfd 作为标识,接下来的两个字节为交易数据的长度,再接下来为交易数据;(即:在标识交易长度方面:使用了3个字节,1个为标识,2个为实际数据)3 交易数据长度 <= 4294967295 byte; 使用一个字节 0xfe 作为标识,接下来的四个字节为交易数据的长度,再接下来为交易数据;(即:在标识交易长度方面:使用了5个字节,1个为标识,4个为实际数据)4 交易数据长度 > 4294967295 byte; 使用使用一个字节 0xfe 作为标识,接下来的八个字节为交易数据的长度,再接下来为交易数据;(即:在标识交易长度方面:使用了9个字节,1个为标识,8个为实际数据)创币交易(coinbase 交易):
与常规交易不同,创币交易没有输入,不消耗UTXO。它只包含一个被称作coinbase的输入,仅仅用来创建新的比特币。创币交易有一个输出,支付到这个矿工的比特币地址。脚本数据长度:
脚本数据长度分为 5 个等级: 1 dataLenth = 0, OpCode = OP_02 dataLenth = 1, OpCode = OP_1 – OP_16, data= 1–16 dataLenth = 1, OpCode = OP_1NEGATE3 dataLenth <= 75, OpCode = dataLenth4 dataLenth <= 255, OpCode = OP_PUSHDATA15 dataLenth <= 65535, OpCode = OP_PUSHDATA2脚本操作码
表示长度的操作码 1 OP_0(0x00) 一个空字符串被压入栈2 OP_1,OP_TRUE(0x51) 1 数字1被压入栈3 OP_2-OP_16(0x52-0x60) 数字(2-16)被压入栈4 OP_PUSHDATA1(0x4c==76) 接下来一个字节标识:脚本数据长度5 OP_PUSHDATA2(0x4d==77) 接下来两个字节标识:脚本数据长度6 OP_PUSHDATA4(0x4e==78) 接下来四个字节标识:脚本数据长度5 当脚本长度 < OP_PUSHDATA1, 该字节直接表示脚本数据的长度. P2SH 的脚本概括 1 脚本字节总数 23 byte2 脚本的第一个字节: OP_HASH160 操作码;3 脚本的第二个字节: 0x14(20), 脚本数据的长度4 脚本的数据 随后20个字节,(内容为脚本哈希)5 最后一个字节 OP_EQUAL 操作码 脚本数据操作 1 OP_EQUAL : 输入相等返回1,否则返回 0;2 OP_HASH160(169) : 输入哈希两次,第一次sha-256,第二次ripemd-160; 数字替代操作符 1 0x80 : 可以用来表示脚本数据值为:负零2 0x81 : 可以用来表示脚本数据值为:-1对应的操作码 : OP_1NEGATE, -1入栈 3 false : 用来表示任何 零。4 true : 用来标识任何 非零。5 正 0 : 通过0长度向量表示 保留字(使用保留字将导致交易失败) 1 OP_RESERVED, 导致交易失败,除非在为执行的条件分支中。控制流 1 OP_IF (0x63)2 OP_NOTIF (0x64)3 OP_VERIF (0x65) 保留字,当出现在未执行的分支中,导致交易失败4 OP_VERNOTIF (0x66) 保留字,当出现在未执行的分支中,导致交易失败5 OP_ELSE (0x67) 6 OP_ENDIF (0x68)7 OP_NOP (0x61) Do Nothing。时间戳 1 OP_CHECKLOCKTIMEVERIFY (0xb1) 描述:标识交易无效:如果栈顶项大于交易时间戳字段,否则,脚本继续执行,就像执行OP_NOP一样。交易无效 : 1.栈顶为空;2.栈顶项为负;3.栈顶项大于等于 5亿,然而交易时间戳字段小于5亿,或者相反的情况,都算失败; 4.交易输入序列字段等于0xffffffff. 2 OP_CHECKSEQUENCEVERIFY (0xb2) 描述:标识交易无效:如果交易输入的相对锁定时间不等于或大于栈顶项的值。(交易输入nSequence字段:由BIP68强制执行)脚本限制: 1 每个脚本最大操作码个数为 : 2012 OP_16 : 什么东西? 3 脚本的最大字节为 10000 字节。签名的限制:
1 长度范围:9 <= size <= 73公钥格式:
压缩公钥 lenth = 33, 并且首字节为 0x02 或者 0x03未压缩公钥 lenth = 65, 并且首字节为 0x04其他都为格式错误的公钥闪电网络
闪电网络的关键技术有三,后后依赖于前前,依次是:RSMC(序列到期可撤销合约),HTLC(哈希时间锁定合约)和闪电网络。RSMC 1 闪电网络的基础是交易双方之间的双向微支付通道,RSMC定义了该双向微支付通道的最基本工作方式。2 微支付通道中沉淀了一部分资金,通道也记录有双方对资金的分配方案。通道的设立会记录在比特币区块链上。3 为了鼓励双方尽可能久地利用通道进行交易,RSMC对主动终止通道方给予了一定的惩罚:主动提出方其资金到账将比对方晚,因此谁发起谁吃亏。4 通道余额分配方案的本质是结算准备金。在此安排下,因为要完全控制资金交收风险,每笔交易都不能突破当前结算准备金所施限制。Txmessage 验证
1 自我格式校验2 链上的校验 1 从mempool取 preOut Tx, 判断该交易此时的状态 0 mempool 为未确认的交易1 orPhen 交易2 OK的交易(已经验证过的)2 从blockChain 取preOut Tx,(这个应该去掉)3 UTXO中 0 UTXO 中都为已经确认的交易 1 3 Tx需要添加一个状态,是否为孤立交易。blockMessage 验证进入mempool的交易:
1 打包的交易脚本包含的内容:
1 签名脚本包含两部分: 签名和公钥 公钥必须匹配上个交易输出锁定脚本中的公钥哈希, 同时这个公钥被用来验证 当前的签名。签名脚本总字节数为:106byte;其中:交易签名:72 byte; 公钥:33 byte; 再加入首字节 0x47,特殊的交易输出,导致的特殊结果
1 在锁定脚本中,标记交易为不可花费采用的是如下这种形式(即:任何人都不可以花费这笔交易,同时这笔交易也不会被计入UTXO集): scriptPubkey : OP_RETURN2 任何人都可以花费的交易签名类型:
1 签名分为三类: SIGHASH_ALL, SIGHASH_NONE, SIGHASH_SINGLE。2 SIGHASH_ALL: 默认类型,目前绝大部分交易采用的,即:签整单交易。组织所有输出、输入,就像上文分解Hex过程一样,每个输入都对应一个签名,暂时留空,其他包括sequence等字段均须填写,这样就形成了一个完整的交易Hex(只缺签名字段)。然后,每一个输入均需使用私钥对该段数据进行签名,签名完成后各自填入相应的位置,N个输入N个签名。简单理解就是:对于该笔单子,认可且只认可的这些输入、输出,并同意花费我的那笔输入。3 SIGHASH_SINGLE: 该签名类型其次自由松散,仅对自己的输入、输出签名,并留空sequence字段。其输入的次序对应其输出的次序,比如输入是第3个,那么签名的输出也是第三个。简单理解就是:我同意花费我的那笔钱,且只能花费到我认可的输出,至于单子里的其他输入、输出,我不关心。4 SIGHASH_NONE 该签名类型是最自由松散的,仅对输入签名,不对输出签名,输出可以任意指定。某人对某笔币签名后交给你,你可以在任意时刻填入任意接受地址,广播出去令其生效。简单理解就是:我同意花费我的那笔钱,至于给谁,我不关心。交易输入签名的生成:
交易签名使用命令: signrawtransaction <hex string> \ [{"txid":txid,"vout":n,"scriptPubKey":hex,"redeemScript":hex},...] [<privatekey1>,...] \ [sighashtype="ALL"] 第一个参数是创建的待签名交易的十六进制字符串;第二个参数有点类似创建交易时的参数,不过需要多出一个公钥字段scriptPubKey,其他节点验证交易时是通过公钥和签名来完成的,所以要提供公钥;如果是合成地址,则需要提供redeemScript第三个参数是即将花费的币所在地址的私钥,用来对交易进行签名,如果该地址私钥已经导入至bitcoind中,则无需显式提供;第四个参数表示签名类型,三种交易签名类型;该命令输出: 输出为完整的交易16进制字符串,内容为一个交易完整的交易结构,签名内容会自动填充进 签名字段。解析输出命令: bitcoind decoderawtransaction : 签名命令后输出的内容。创建待发送交易: 创建待发送交易,由命令:createrawtransaction [{“txid”:txid,”vout”:n},…] {address:amount,…}来完成。创建一笔:将 0.1 BTC发送至 1Q8s4qDRbCbFypG5AFNR9tFC57PStkPX1x ,并支付 0.0001 BTC做为矿工费。输入交易的额度为 0.199 ,输出为 0.1 + 0.0001 = 0.1001 ,那么还剩余: 0.199 - 0.1001 = 0.0989 ,将此作为找零发回给自己。执行命令: bitcoind createrawtransaction \ '[{"txid":"296ea7bf981b44999d689853d17fe0ceb852a8a34e68fcd19f0a41e589132156","vout":0}]' \ '{"1Q8s4qDRbCbFypG5AFNR9tFC57PStkPX1x":0.1, "1Lab618UuWjLmVA1Q64tHZXcLoc4397ZX3":0.0989}'改命令输出:16进制字符串。内容为不包含交易签名的整个完整交易通过命令:decoderawtransaction ,可以将此段十六进制字符串解码,输出如下结构信息。 { "txid" : "54f773a3fdf7cb3292fc76b46c97e536348b3a0715886dbfd2f60e115fb3a8f0", "version" : 1, "locktime" : 0, "vin" : [ { "txid" : "296ea7bf981b44999d689853d17fe0ceb852a8a34e68fcd19f0a41e589132156", "vout" : 0, "scriptSig" : { "asm" : "", "hex" : "" }, "sequence" : 4294967295 } ], "vout" : [ { "value" : 0.10000000, "n" : 0, "scriptPubKey" : { "asm" : "OP_DUP OP_HASH160 fdc7990956642433ea75cabdcc0a9447c5d2b4ee OP_EQUALVERIFY OP_CHECKSIG", "hex" : "76a914fdc7990956642433ea75cabdcc0a9447c5d2b4ee88ac", "reqSigs" : 1, "type" : "pubkeyhash", "addresses" : [ "1Q8s4qDRbCbFypG5AFNR9tFC57PStkPX1x" ] } }, { "value" : 0.09890000, "n" : 1, "scriptPubKey" : { "asm" : "OP_DUP OP_HASH160 d6c492056f3f99692b56967a42b8ad44ce76b67a OP_EQUALVERIFY OP_CHECKSIG", "hex" : "76a914d6c492056f3f99692b56967a42b8ad44ce76b67a88ac", "reqSigs" : 1, "type" : "pubkeyhash", "addresses" : [ "1Lab618UuWjLmVA1Q64tHZXcLoc4397ZX3" ] } } ] } case : hashType & 0x1f: case : 0x10 == 2 (SIGHASH_NONE) case : 0x11 == 3 (SIGHASH_SINGLE) case : 0x01 == 1 (SIGHASH_ALL) //一个完整的交易 type Tx struct { Hash utils.Hash //本交易的哈希 LockTime uint32 //交易时间戳 Version int32 //版本号 Ins []*TxIn //交易输入 Outs []*TxOut //交易输出 } //交易输入 type TxIn struct { PreviousOutPoint *OutPoint //引用的UTXO ScriptSig []byte //签名脚本 Sequence uint32 //todo ? } //指向输入中引用的UTXO type OutPoint struct { Hash *utils.Hash //该 UTXO 交易的哈希 Index uint32 //该 UTXO的索引号 } //交易输出 type TxOut struct { Value int64 //交易币值 OutScript []byte //锁定脚本 } // digest represents the partial evaluation of a checksum. // 摘要表示对校验和的部分求值 type digest struct { h [8]uint32 x [chunk]byte nx int len uint64 is224 bool // mark if this digest is SHA-224 } //解析后的脚本结构 type ParsedOpCode struct { opValue byte //操作码 length int //四种情况, 1:data为nil; -1:数据长度用一个字节标识;-2:数据长度用两个字节标识;-4:数据长度用四个字节标识 data []byte //脚本数据 } 3Bzt3JA9eebS2FcgGpSSQDETmewhJUWjFs // type ScriptFreeList chan []byte var scriptPool ScriptFreeList = make(chan []byte, FreeListMaxItems)