工作,学习,生活,这里将会有一些记录. 备用域名:http://meisw.wdlinux.cn 注册 | 登陆
浏览模式: 标准 | 列表全部文章

比特币交易签名过程详解

 最近在研究比特币交易签名计算,网上没有完整介绍签名过程的例子。本文力图提供一个完整例子,详细介绍比特币签名的计算过程。

1. 比特币交易的格式

交易数据格式

大小   字段名称  数据类型     描述

4字节  协议版本   uint32_t    明确这笔交易参照的规则协议的版本号

1-9字节 输入数量   var_int   被包含的输入交易的数量

不定   输入列表   tx_in[]    一个或多个输入交易构成的数组

1-9字节 输出数量   var_int   被包含的输出交易的数量

不定   输出列表   tx_out[]   一个或多个输出交易构成的数组

4字节  锁定时间   uint32_t    一个UNIX时间戳或区块号

tx_in 格式

其中tx_in 包括:

字段尺寸

描述

数据类型

说明

36

previous_output

outpoint

对前一输出的引用

1+

script length

var_int

signature script 的长度

?

signature script

uchar[]

用于确认交易授权的计算脚本

4

sequence

unit32_t

Used for locktime or disabled(0xFFFFFFFF)

 

OutPoint结构的构成:

字段尺寸

描述

数据类型

说明

32

hash

char[32]

引用的交易的散列

4

index

uint32_t

指定输出的索引,第一笔输出的索引是0,以此类推

tx_out的构成:

字段尺寸

描述

数据类型

说明

8

value

uint64_t

交易的比特币数量(单位是0.00000001)

1+

pk_script

var_int

pk_script的长度

?

pk_script

uchar[]

Usually contains the public key as a Bitcoin script setting up conditions to claim this output

 

2. 签名计算:

将其他输入的pkscript长度调整为0,并末尾加上四字节小端序的sighash_type,并进行两次sha256:

在对这个hash进行签名计算,得出签名数据(签名时不用再计算hash,直接调用ecdsa-sign-digest)

3. 计算示例

使用electrum生成的未签名数据示例:

0100000001b37b9eefc3fa245f5ce36cb51c2d18a2d16e19d20867b23130e00f5280ccf82d010000002401ff210395cf5234e602954cba693138f3ba94c1cde7337675f5a94931e6226802d74d16fdffffff02002d3101000000001976a91425dc469afb4654d27742e3669bb3f5812268f2a188ac9ec2c901000000001976a9142dbbbd8bcff08a549be21efae747592049c9dc2d88ac71221300

 

签名后的数据:

0100000001b37b9eefc3fa245f5ce36cb51c2d18a2d16e19d20867b23130e00f5280ccf82d010000006a47304402202008714016f7e01c1a0010d7e6eb0b1f100b5a9b7c65a0506d62c1fbb9790cb102203daf6363c4039a739036ce152817f73d31319f060bbf5f354a0eeaf9f7ed3cd001210395cf5234e602954cba693138f3ba94c1cde7337675f5a94931e6226802d74d16fdffffff02002d3101000000001976a91425dc469afb4654d27742e3669bb3f5812268f2a188ac9ec2c901000000001976a9142dbbbd8bcff08a549be21efae747592049c9dc2d88ac71221300

交易记录:

https://www.blocktrail.com/tBTC/tx/8c6375e4509a186539dbbc2936feef7671f256969c917b633ec5db6b23c78ed1

 

计算过程:

协议版本:01000000

输入数量:01

输入列表:

  • 32字节 前一次交易的hash

         b37b9eefc3fa245f5ce36cb51c2d18a2d16e19d20867b23130e00f5280ccf82d

(默认是大端,要去网上查询详情的话,用的是小端

2df8cc80520fe03031b26708d2196ed1a2182d1cb56ce35c5f24fac3ef9e7bb3)

  • 4字节 前一次交易的输出index : 01000000(序号从0开始)
  • Pkscript 长度:VI (1字节)0x19(25字节)
  • Pkscript:

OP_DUP(76) OP_HASH160(a9) 20字节数据(14)

2dbbbd8bcff08a549be21efae747592049c9dc2d OP_EQUALVERIFY (88)OP_CHECKSIG(ac)

 

1976a9142dbbbd8bcff08a549be21efae747592049c9dc2d88ac

  • Sequence: fdffffff

输出数量:02

输出列表:

  • Value: 8字节 002d310100000000
  • Pkscript长度 0x19 (25)
  • Pkscript:76a91425dc469afb4654d27742e3669bb3f5812268f2a188ac
  • Value:8字节 9ec2c90100000000
  • Pkscript长度 0x19 (25)
  • Pkscript:76a9142dbbbd8bcff08a549be21efae747592049c9dc2d88ac

锁定时间:71221300

HashType :01000000(四字节)

 

两次hash值 (405c87d455f2f26e554c05b657769e2af253135367bcc69d4d772f873d39a23c)

进行2次sha256后,调用ecdsa_verify_digest计算签名,不需要在对2次sha256后的数据进行hash后再计算签名

签名值:r,s:

2008714016f7e01c1a0010d7e6eb0b1f100b5a9b7c65a0506d62c1fbb9790cb1

3daf6363c4039a739036ce152817f73d31319f060bbf5f354a0eeaf9f7ed3cd0

Pubk为0395cf5234e602954cba693138f3ba94c1cde7337675f5a94931e6226802d74d16

比特币地址生成过程详解

 

1. 比特币地址编码格式

比特币地址采用base58 check格式编码

Base 58 check编码方法如下图所示:

2. 比特币地址计算详细过程

比特币地址计算过程如下图所示:

以普通公钥地址计算过程为例:

1. 如未压缩公钥为:

04 5c0de3b9c8ab18dd04e3511243ec2952002dbfadc864b9628910169d9b9b00ec243bcefdd4347074d44bd7356d6a53c495737dd96295e2a9374bf5f02ebfc176

2. 经过sha256和 ripemd160 hash计算后结果为

09c6e71118d8f12bec6b5c61884b35677c0a0ae3

3. base58check编码

3.1 添加前缀0x00结果为0009c6e71118d8f12bec6b5c61884b35677c0a0ae3

3.2 计算double sha256 结果为2a021f87fa371ae2a63dd44112bf3175039e9a96613734309ca87fda7862a301

取前四字节

3.3 前缀+DATA+checksum为:

0009c6e71118d8f12bec6b5c61884b35677c0a0ae32a021f

3.4 base58 编码结果为

Bitcoin Address (b58check) is:

1thMirt546nngXqyPEz532S8fLwbozud8

同样可以用压缩公钥

025c0de3b9c8ab18dd04e3511243ec2952002dbfadc864b9628910169d9b9b00ec

生成一个压缩公钥对应的地址

Compressed Bitcoin Address (b58check) is:

14cxpo3MBCYYWCgF74SWTdcmxipnGUsPw3

 

所以一个私钥可以生成2个比特币的地址,公钥和压缩公钥都可以生成对应的比特币地址

 

参考文献:《精通比特币(第二版)》

比特币交易手续费详解

 人们经常说你可以免费将比特币发送到地球的任意角落,通常情况下的确可以免费转账,但是在某些情况下你必须支付手续费(Transaction Fees)才能完成转账, 在0.8.3版Bitcoin钱包中默认是0.0001比特币的转账手续费。 这个手续费是奖励给矿工的,以激励矿工继续挖矿为比特币提供足够的算力从而确保比特币网络的安全。目前矿工的主要收入是通过创造新的块(Block)来获得25BTC的奖励,但是这个奖励每4年减半,随着时间的推移比特币交易手续费奖励将逐渐取代创造新块的奖励。 什么情况下需要支付手续费?比特币手续费收取多少?手续费怎么算? 比特币系统有一系列的网络规则,其中包含手续费规则,这一系列规则也就是“客户端要做什么”。当你使用Bitcoin客户端(钱包,Bitcoin-Qt)发送比特币的时候,整个过程大致分为以下步骤:

 

1. 筹备你要发送的比特币。客户端负责收集你钱包(Bitcoin-Qt)里的比特币余额为支付做准备,因为你收到的每一笔比特币都存在你的钱包里面直到你花掉它们。 假如你收到3BTC与2BTC两次付款,它们在钱包的记录是相互独立的,即一个3BTC和一个2BTC,而不是合并为5BTC(钱包只记录交易明细,并不将余额合并,但是你在钱包的界面上可以看到总的余额),随着时间的推移你的钱包里会积累许多这样数量不等的比特币,所以当你发送比特币的时候钱包必须决定用哪些比特币最适合用来本次发送。 在一次交易中你得到的比特币称为“输入(inputs)”,支出的比特币称为“输出(outputs)”,在你的钱包里存在多个输入和输出。

 

2. 阻止大量微额(dust)支付冲击网络。如果你的输出(outputs)小于0.01BTC(包括你钱包内部的资金变动)的话,你必须要支付0.0001的手续费,即使是你自己转给你自己。钱包在准备你的支付金额的时候有一个既定的规则,就是在众多输入(inputs)中筹备支付金额的时候尽量避免产生小于0.01BTC的金额变动(比如你要支付5.005BTC,钱包尽可能的选择3+2.005或者1+1+3.005,而不是5+0.005)。

 

3. 数额越大、币龄(age)越高优先级越高。如果你发送金额太小或者是你的比特币刚开采出来不久,那么你的转账就不再免费之列。每一个交易都会分配一个优先级,这个优先级通过币的新旧程度、交易的字节数和交易的数量。具体来说,对于每一个输入(inputs)来讲,客户端会先将比特币的数量乘以这些币在块中存在的时间(币龄,age),然后将所有的乘积加起来除以此次交易的大小(以字节为单位),计算公式:priority = sum(input_value_in_base_units * input_age)/size_in_bytes,计算结果如果小于0.576,那么该交易就必须支付手续费。如果你确实大量的小额输入,又想免费转出,这时候你可以加一个数额大的、币龄大的比特币金额,就会将平均优先级提高,从而可以免费转出比特币。

 

4. 每千字节的收费。在转账的最后客户端会检测本次转账的大小(以字节为单位),大小一般取决于输入和输出的数额大小,计算公式如下:148 * 输入数额 + 34 * 输出数额 + 10,如果该次转账的大小超过10000字节但是优先级符合免费的标准,那么仍然可以享受免费转账,否则需要支付手续费。没1000字节的费用默认是0.0001BTC,但是你也可以在客户端里进行追加,依次打开选项卡“设置>选项>主要”进行手续费的调整。如果你在设置的手续费小于0.0001BTC按0.0001算。

Golang同步:条件变量和锁组合使用

 https://studygolang.com/articles/5776

golang 1.8 并发安全Map简单实现

XML/HTML代码
  1. type SafeMap struct {  
  2.     sync.RWMutex  
  3.     Map map[int64]string  
  4. }  
  5.   
  6. func NewSafeMap(size int) *SafeMap {  
  7.     sm :new(SafeMap)  
  8.     sm.Map = make(map[int64]string, size)  
  9.     return sm  
  10. }  
  11.   
  12. func (sm *SafeMap) ReadMap(key int64) string {  
  13.     sm.RLock()  
  14.     value :sm.Map[key]  
  15.     sm.RUnlock()  
  16.     return value  
  17. }  
  18.   
  19. func (sm *SafeMap) WriteMap(key int64, value string) {  
  20.     sm.Lock()  
  21.     sm.Map[key] = value  
  22.     sm.Unlock()  
  23. }  
  24.   
  25. // 用于for k,_ :range m.Keys(){v :m.ReadMap(k) ....}  
  26. func (sm *SafeMap) Keys() []int64 {  
  27.     sm.RLock()  
  28.     value :make([]int64, 0)  
  29.     for k, _ :range sm.Map {  
  30.         value = append(value, k)  
  31.     }  
  32.     sm.RUnlock()  
  33.     return value  
  34. }  

https://blog.csdn.net/qq_17612199/article/details/79601222

golang:An operation on a socket could not be performed because the system lacked sufficient buffer s

 1、问题 

conn, err := net.Dial(“tcp”, ‘127.0.0.1:50001’)

执行此语句报错详细报错信息 
dial tcp 127.0.0.1:50001: An operation on a socket could not be performed because the system lacked sufficient buffer space or because a queue was full.

此报错的原因一般是系统端口已用尽,无法再建立新的Socket连接

https://blog.csdn.net/xia_xing/article/details/53352658

服务器 TIME_WAIT和CLOSE_WAIT

https://blog.csdn.net/xia_xing/article/details/53352486

常见SOCKET错误参数

https://blog.csdn.net/macky0668/article/details/4257721

 

 

MySQL 事务没有提交导致 锁等待 Lock wait timeout exceeded

 

MySQL 5.5 -- innodb_lock_wait 锁 等待

记得以前,当出现:ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction,
要解决是一件麻烦的事情 ;
特别是当一个SQL执行完了,但未COMMIT,后面的SQL想要执行就是被锁,超时结束;
DBA光从数据库无法着手找出源头是哪个SQL锁住了;
有时候看看show engine innodb status , 并结合 show full processlist; 能暂时解决问题;但一直不能精确定位;

在5.5中,information_schema 库中增加了三个关于锁的表(MEMORY引擎);
innodb_trx ## 当前运行的所有事务
innodb_locks ## 当前出现的锁
innodb_lock_waits ## 锁等待的对应关系

看到这个就非常激动 ; 这可是解决了一个大麻烦,先来看一下表结构

https://blog.csdn.net/mangmang2012/article/details/9207007

mysql中set autocommit=0与start transaction区别

 set autocommit=0指事务非自动提交,自此句执行以后,每个SQL语句或者语句块所在的事务都需要显示"commit"才能提交事务。

 

 

1、不管autocommit 是1还是0 
     START TRANSACTION 后,只有当commit数据才会生效,ROLLBACK后就会回滚。

 

2、当autocommit 为 0 时
    不管有没有START TRANSACTION。
    只有当commit数据才会生效,ROLLBACK后就会回滚。

 

3、如果autocommit 为1 ,并且没有START TRANSACTION 。
    调用ROLLBACK是没有用的。即便设置了SAVEPOINT。

Records:107012345678910»