-
Notifications
You must be signed in to change notification settings - Fork 42
/
block.go
108 lines (77 loc) · 2.37 KB
/
block.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
103
104
105
106
107
108
package wavelet
import (
"encoding/binary"
"encoding/hex"
"fmt"
"io"
"reflect"
"unsafe"
"github.com/pkg/errors"
"golang.org/x/crypto/blake2b"
)
type Block struct {
Index uint64
Merkle MerkleNodeID
Transactions []TransactionID
ID BlockID
}
func NewBlock(index uint64, merkle MerkleNodeID, ids ...TransactionID) Block {
b := Block{Index: index, Merkle: merkle, Transactions: ids}
b.ID = blake2b.Sum256(b.Marshal())
return b
}
func (b *Block) GetID() string {
if b == nil || b.ID == ZeroBlockID {
return ""
}
return fmt.Sprintf("%x", b.ID)
}
func (b Block) Marshal() []byte {
buf, n := make([]byte, 8+SizeMerkleNodeID+4+len(b.Transactions)*SizeTransactionID), 0
binary.BigEndian.PutUint64(buf[n:n+8], b.Index)
n += 8
copy(buf[n:n+SizeMerkleNodeID], b.Merkle[:])
n += SizeMerkleNodeID
binary.BigEndian.PutUint32(buf[n:n+4], uint32(len(b.Transactions)))
n += 4
// Directly convert the slice of transaction IDs into a byte slice through
// pointer re-alignment. This is done by taking the internal pointer of
// (*Block).Transactions, and re-assigning the pointer to an empty
// byte slice.
{
var ids []byte
sh := (*reflect.SliceHeader)(unsafe.Pointer(&ids))
sh.Data = (*reflect.SliceHeader)(unsafe.Pointer(&b.Transactions)).Data
sh.Len = SizeTransactionID * len(b.Transactions)
sh.Cap = SizeTransactionID * len(b.Transactions)
copy(buf[n:n+len(b.Transactions)*SizeTransactionID], ids)
}
return buf
}
func (b Block) String() string {
return hex.EncodeToString(b.ID[:])
}
func UnmarshalBlock(r io.Reader) (Block, error) {
var (
buf [8]byte
block Block
)
if _, err := io.ReadFull(r, buf[:]); err != nil {
return block, errors.Wrap(err, "failed to decode block index")
}
block.Index = binary.BigEndian.Uint64(buf[:8])
if _, err := io.ReadFull(r, block.Merkle[:]); err != nil {
return block, errors.Wrap(err, "failed to decode block's merkle root")
}
if _, err := io.ReadFull(r, buf[:4]); err != nil {
return block, errors.Wrap(err, "failed to decode block's transactions length")
}
block.Transactions = make([]TransactionID, binary.BigEndian.Uint32(buf[:4]))
for i := 0; i < len(block.Transactions); i++ {
if _, err := io.ReadFull(r, block.Transactions[i][:]); err != nil {
return block, errors.Wrap(err, "failed to decode one of the transactions")
}
}
block.ID = blake2b.Sum256(block.Marshal())
return block, nil
}