我的博客

Python 异常处理

目录
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import sys,traceback

def raiseError(x):
raise IOError("输入/输出失败")


def f():
x = 1
raiseError(x)

try:
f()
except:
exType,exValue,exTrace = sys.exc_info()
print(exType)
print(exType,exValue,sep="\n")
traceback.print_tb(exTrace)
for trace in traceback.extract_tb(exTrace):
print('='*9)
print(str(trace))
print('='*9)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<class 'OSError'>
<class 'OSError'>
输入/输出操作失败
File "C:\Users\Swing\Desktop\a.py", line 12, in <module>
f()
File "C:\Users\Swing\Desktop\a.py", line 9, in f
raiseError(x)
File "C:\Users\Swing\Desktop\a.py", line 4, in raiseError
raise IOError("输入/输出操作失败")
None
=========
<FrameSummary file C:\Users\Swing\Desktop\a.py, line 12 in <module>>
=========
=========
<FrameSummary file C:\Users\Swing\Desktop\a.py, line 9 in f>
=========
=========
<FrameSummary file C:\Users\Swing\Desktop\a.py, line 4 in raiseError>
=========

比特币协议解读

目录
  1. 哈希
  2. 默克尔树(Merkle Trees)
  3. 签名算法
  4. 交易验证
  5. 地址
  6. 数据结构
    1. 消息
    2. 变长整数
    3. 变长字符串
    4. 网络地址
    5. Inventory Vectors
    6. 区块头
    7. Differential encoding
    8. PrefilledTransaction
    9. HeaderAndShortIDs
    10. BlockTransactionsRequest
    11. BlockTransactions
    12. Short transaction ID
  7. 信息类型
    1. version
    2. verack
    3. addr
    4. inv
    5. getdata
    6. notfound
    7. getblocks
    8. getheaders
    9. tx
    10. block
    11. headers
    12. getaddr
    13. mempool
    14. checkorder
    15. submitorder
    16. reply
    17. ping
    18. pong
    19. reject
    20. filterload, filteradd, filterclear, merkleblock
    21. alert
    22. sendheaders
    23. feefilter
    24. sendcmpct
    25. cmpctblock
    26. getblocktxn
    27. blocktxn
  8. 协议流程

参考资料:https://en.bitcoin.it/wiki/Protocol_documentation

哈希

比特币系统中用到的两种哈希函数

  1. SHA-256
  2. RIPEMD-160

默克尔树(Merkle Trees)

graph TD
    node1["d1=hash(a)"] --> dataa((a))
    node2["d2=hash(b)"] --> datab((b))
    node3["d3=hash(c)"] --> datac((c))
    node4["d4=hash(c)"] --> datac((c))
    node5["d5=hash(d1+d2)"] --> node1
    node5 --> node2
    node6["d6=hash(d3+d4)"] --> node3
    node6 --> node4
    root["树根 d7=hash(d5+d6)"] --> node5
    root --> node6

图中圆形的 a,b,c 是数据(就是比特币系统中的交易),矩形节点 d1 到 d7 是默克尔树,其中 d7 是树根。默克尔树是完全二叉树,所以他的叶子节点数是 2 的 n 次幂,如图中的情况,数据的个数不是 2 的 n 次幂,那么后面的叶子节点的值都是最后一个数据的哈希。

在比特币系统中,交易就是最下面的数据, hash 对应的是两次 sha256。

签名算法

比特币使用 椭圆曲线 数字签名算法 (ECDSA) 给交易签名。

交易验证

  1. input 合法性
    1. 指向一个尚未花费的 output
    2. 提供了它指向的 output 的 script 中所要求的结果
  2. coinbase 交易合法性

地址

比特币地址是一个 ECDSA 公钥的哈希

数据结构

消息

变长整数

变长字符串

网络地址

Inventory Vectors

区块头

Differential encoding

PrefilledTransaction

HeaderAndShortIDs

BlockTransactionsRequest

BlockTransactions

Short transaction ID

信息类型

version

比特币两个节点建立连接以后先要互相发送 version 消息,确保双方版本兼容。

verack

比特币节点对 version 消息的回复。

addr

inv

getdata

notfound

getblocks

getheaders

tx

block

headers

getaddr

mempool

checkorder

submitorder

reply

ping

pong

reject

filterload, filteradd, filterclear, merkleblock

alert

bitcoin.it 上说比特币核心客户端已经于 2016 年 3 月 停止对 alert 消息的支持。但是实际上我在与一些节点交互的过程中发现 Satoshi:0.18.99 的客户端仍然会向我发送 alert 消息。

sendheaders

feefilter

sendcmpct

cmpctblock

getblocktxn

blocktxn

协议流程

客户端发起与 peer 的连接后首先进行 Version Handshake,流程如下:(L 是本地节点,R 是远端节点)

1
2
3
4
5
6
L -> R: Send version message with the local peer's version
R -> L: Send version message back
R -> L: Send verack message
R: Sets version to the minimum of the 2 versions
L -> R: Send verack message after receiving version message from R
L: Sets version to the minimum of the 2 versions

游双秀公园

目录

双秀公园建成于 1984 年 10 月 1 日,是给建国 35 周年的献礼。今年是新中国 70 华诞,而双秀公园也建成整整 35 周年了。

公园北靠北三环,西邻有研大厦,东侧是新风北街(似乎是南北单行),南侧的双秀南巷是个断头路,通着几个小区。因为公园由清雅俊秀的中国园和山秀水清的日本园组成,所以叫双秀公园。

Read More

golang mongo-driver 源码阅读 SingleResult.Decode

目录
  1. 主要流程
  2. StructCodec.describeStruct
  3. reflect.Value.Field
  4. reflect.Value.FieldByIndex

主要流程

SingleResult 是 Collection.FindOne 的返回结果的类型。

Collection 的代码在 go.mongodb.org\mongo-driver\mongo\collection.go

FindOne 返回的类型是 SingleResult。

SingleResult 在 go.mongodb.org\mongo-driver\mongo\single_result.go

我们看到 Decode 函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// Decode will attempt to decode the first document into v. If there was an
// error from the operation that created this SingleResult then the error
// will be returned. If there were no returned documents, ErrNoDocuments is
// returned. If v is nil or is a typed nil, an error will be returned.
func (sr *SingleResult) Decode(v interface{}) error {
if sr.err != nil {
return sr.err
}
if sr.reg == nil {
return bson.ErrNilRegistry
}

if sr.err = sr.setRdrContents(); sr.err != nil {
return sr.err
}
return bson.UnmarshalWithRegistry(sr.reg, sr.rdr, v)
}

再看 bson 的 UnmarshalWithRegistry

go.mongodb.org\mongo-driver\bson\unmarshal.go

1
2
3
4
5
6
7
// UnmarshalWithRegistry parses the BSON-encoded data using Registry r and
// stores the result in the value pointed to by val. If val is nil or not
// a pointer, UnmarshalWithRegistry returns InvalidUnmarshalError.
func UnmarshalWithRegistry(r *bsoncodec.Registry, data []byte, val interface{}) error {
vr := bsonrw.NewBSONDocumentReader(data)
return unmarshalFromReader(bsoncodec.DecodeContext{Registry: r}, vr, val)
}

再看下文的 unmarshalFromReader

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
func unmarshalFromReader(dc bsoncodec.DecodeContext, vr bsonrw.ValueReader, val interface{}) error {
dec := decPool.Get().(*Decoder)
defer decPool.Put(dec)

err := dec.Reset(vr)
if err != nil {
return err
}
err = dec.SetContext(dc)
if err != nil {
return err
}

return dec.Decode(val)
}

再看 Decoder.Decode 在 go.mongodb.org\mongo-driver\bson\decoder.go

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
26
27
28
29
// Decode reads the next BSON document from the stream and decodes it into the
// value pointed to by val.
//
// The documentation for Unmarshal contains details about of BSON into a Go
// value.
func (d *Decoder) Decode(val interface{}) error {
if unmarshaler, ok := val.(Unmarshaler); ok {
// TODO(skriptble): Reuse a []byte here and use the AppendDocumentBytes method.
buf, err := bsonrw.Copier{}.CopyDocumentToBytes(d.vr)
if err != nil {
return err
}
return unmarshaler.UnmarshalBSON(buf)
}

rval := reflect.ValueOf(val)
if rval.Kind() != reflect.Ptr {
return fmt.Errorf("argument to Decode must be a pointer to a type, but got %v", rval)
}
if rval.IsNil() {
return ErrDecodeToNil
}
rval = rval.Elem()
decoder, err := d.dc.LookupDecoder(rval.Type())
if err != nil {
return err
}
return decoder.DecodeValue(d.dc, d.vr, rval)
}

再看 ValueDecoder.DecodeValue 声明在

go.mongodb.org\mongo-driver\bson\bsoncodec\bsoncodec.go

我们这里的参数是 struct ,执行的是

go.mongodb.org\mongo-driver\bson\bsoncodec\struct_codec.go

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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
// DecodeValue implements the Codec interface.
// By default, map types in val will not be cleared. If a map has existing key/value pairs, it will be extended with the new ones from vr.
// For slices, the decoder will set the length of the slice to zero and append all elements. The underlying array will not be cleared.
func (sc *StructCodec) DecodeValue(r DecodeContext, vr bsonrw.ValueReader, val reflect.Value) error {
if !val.CanSet() || val.Kind() != reflect.Struct {
return ValueDecoderError{Name: "StructCodec.DecodeValue", Kinds: []reflect.Kind{reflect.Struct}, Received: val}
}

switch vr.Type() {
case bsontype.Type(0), bsontype.EmbeddedDocument:
default:
return fmt.Errorf("cannot decode %v into a %s", vr.Type(), val.Type())
}

sd, err := sc.describeStruct(r.Registry, val.Type())
if err != nil {
return err
}

var decoder ValueDecoder
var inlineMap reflect.Value
if sd.inlineMap >= 0 {
inlineMap = val.Field(sd.inlineMap)
if inlineMap.IsNil() {
inlineMap.Set(reflect.MakeMap(inlineMap.Type()))
}
decoder, err = r.LookupDecoder(inlineMap.Type().Elem())
if err != nil {
return err
}
}

dr, err := vr.ReadDocument()
if err != nil {
return err
}

for {
name, vr, err := dr.ReadElement()
if err == bsonrw.ErrEOD {
break
}
if err != nil {
return err
}

fd, exists := sd.fm[name]
if !exists {
if sd.inlineMap < 0 {
// The encoding/json package requires a flag to return on error for non-existent fields.
// This functionality seems appropriate for the struct codec.
err = vr.Skip()
if err != nil {
return err
}
continue
}

elem := reflect.New(inlineMap.Type().Elem()).Elem()
err = decoder.DecodeValue(r, vr, elem)
if err != nil {
return err
}
inlineMap.SetMapIndex(reflect.ValueOf(name), elem)
continue
}

var field reflect.Value
if fd.inline == nil {
field = val.Field(fd.idx)
} else {
field = val.FieldByIndex(fd.inline)
}

if !field.CanSet() { // Being settable is a super set of being addressable.
return fmt.Errorf("cannot decode element '%s' into field %v; it is not settable", name, field)
}
if field.Kind() == reflect.Ptr && field.IsNil() {
field.Set(reflect.New(field.Type().Elem()))
}
field = field.Addr()

dctx := DecodeContext{Registry: r.Registry, Truncate: fd.truncate}
if fd.decoder == nil {
return ErrNoDecoder{Type: field.Elem().Type()}
}

if decoder, ok := fd.decoder.(ValueDecoder); ok {
err = decoder.DecodeValue(dctx, vr, field.Elem())
if err != nil {
return err
}
continue
}
err = fd.decoder.DecodeValue(dctx, vr, field)
if err != nil {
return err
}
}

return nil
}

这次这个比较长,但是终于到此为止了。

把查询到的数据赋给我们的变量的过程在 38 行的 for 循环中进行。

39 行,读取一对键值;40 行,如果没取到(已读完所有数据),则退出;
47 - 66 行,判断读取到的值在我们传入的结构体中是否存在,如果不存在则 continue;

StructCodec.describeStruct

(待读)

reflect.Value.Field

Go\src\reflect\value.go

reflect.Value.FieldByIndex

Go\src\reflect\value.go

beego 数据库 ORM 操作

目录
  1. migrate
    1. 命令模式
    2. 更新表结构而不删除数据
  2. 其他

migrate

命令模式

修改 main.go

1
2
3
4
5
6
func main() {
// orm.RegisterModel...
// orm.RegisterDataBase...
...
orm.RunCommand()
}

然后执行

1
2
go build main.go
./main orm

可以查看可用的命令

更新表结构而不删除数据

修改 main.go

1
2
3
4
5
6
func main() {
// orm.RegisterModel...
// orm.RegisterDataBase...
...
orm.RunSyncdb("default", false, true)
}

其他

默认值设置

1
2
3
4
5
type TraceBackTask struct {
Id int
Status string
Visible bool `omr:"default(true)"`
}