forked from AplaProject/go-apla
/
serialization.go
126 lines (107 loc) · 4.33 KB
/
serialization.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
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
package block
import (
"bytes"
"fmt"
"github.com/GenesisCommunity/go-genesis/packages/consts"
"github.com/GenesisCommunity/go-genesis/packages/converter"
"github.com/GenesisCommunity/go-genesis/packages/crypto"
"github.com/GenesisCommunity/go-genesis/packages/transaction"
"github.com/GenesisCommunity/go-genesis/packages/utils"
log "github.com/sirupsen/logrus"
)
// MarshallBlock is marshalling block
func MarshallBlock(header *utils.BlockData, trData [][]byte, prevHash []byte, key string) ([]byte, error) {
var mrklArray [][]byte
var blockDataTx []byte
var signed []byte
logger := log.WithFields(log.Fields{"block_id": header.BlockID, "block_hash": header.Hash, "block_time": header.Time, "block_version": header.Version, "block_wallet_id": header.KeyID, "block_state_id": header.EcosystemID})
for _, tr := range trData {
doubleHash, err := crypto.DoubleHash(tr)
if err != nil {
logger.WithFields(log.Fields{"type": consts.CryptoError, "error": err}).Error("double hashing transaction")
return nil, err
}
mrklArray = append(mrklArray, converter.BinToHex(doubleHash))
blockDataTx = append(blockDataTx, converter.EncodeLengthPlusData(tr)...)
}
if key != "" {
if len(mrklArray) == 0 {
mrklArray = append(mrklArray, []byte("0"))
}
mrklRoot := utils.MerkleTreeRoot(mrklArray)
forSign := fmt.Sprintf("0,%d,%x,%d,%d,%d,%d,%s",
header.BlockID, prevHash, header.Time, header.EcosystemID, header.KeyID, header.NodePosition, mrklRoot)
var err error
signed, err = crypto.Sign(key, forSign)
if err != nil {
logger.WithFields(log.Fields{"type": consts.CryptoError, "error": err}).Error("signing blocko")
return nil, err
}
}
var buf bytes.Buffer
// fill header
buf.Write(converter.DecToBin(header.Version, 2))
buf.Write(converter.DecToBin(header.BlockID, 4))
buf.Write(converter.DecToBin(header.Time, 4))
buf.Write(converter.DecToBin(header.EcosystemID, 4))
buf.Write(converter.EncodeLenInt64InPlace(header.KeyID))
buf.Write(converter.DecToBin(header.NodePosition, 1))
buf.Write(converter.EncodeLengthPlusData(signed))
// data
buf.Write(blockDataTx)
return buf.Bytes(), nil
}
func UnmarshallBlock(blockBuffer *bytes.Buffer, firstBlock bool) (*Block, error) {
header, err := utils.ParseBlockHeader(blockBuffer, !firstBlock)
if err != nil {
return nil, err
}
logger := log.WithFields(log.Fields{"block_id": header.BlockID, "block_time": header.Time, "block_wallet_id": header.KeyID,
"block_state_id": header.EcosystemID, "block_hash": header.Hash, "block_version": header.Version})
transactions := make([]*transaction.Transaction, 0)
var mrklSlice [][]byte
// parse transactions
for blockBuffer.Len() > 0 {
transactionSize, err := converter.DecodeLengthBuf(blockBuffer)
if err != nil {
logger.WithFields(log.Fields{"type": consts.UnmarshallingError, "error": err}).Error("transaction size is 0")
return nil, fmt.Errorf("bad block format (%s)", err)
}
if blockBuffer.Len() < int(transactionSize) {
logger.WithFields(log.Fields{"size": blockBuffer.Len(), "match_size": int(transactionSize), "type": consts.SizeDoesNotMatch}).Error("transaction size does not matches encoded length")
return nil, fmt.Errorf("bad block format (transaction len is too big: %d)", transactionSize)
}
if transactionSize == 0 {
logger.WithFields(log.Fields{"type": consts.EmptyObject}).Error("transaction size is 0")
return nil, fmt.Errorf("transaction size is 0")
}
bufTransaction := bytes.NewBuffer(blockBuffer.Next(int(transactionSize)))
t, err := transaction.UnmarshallTransaction(bufTransaction)
if err != nil {
if t != nil && t.TxHash != nil {
transaction.MarkTransactionBad(t.DbTransaction, t.TxHash, err.Error())
}
return nil, fmt.Errorf("parse transaction error(%s)", err)
}
t.BlockData = &header
transactions = append(transactions, t)
// build merkle tree
if len(t.TxFullData) > 0 {
dSha256Hash, err := crypto.DoubleHash(t.TxFullData)
if err != nil {
logger.WithFields(log.Fields{"type": consts.CryptoError, "error": err}).Error("double hashing tx full data")
return nil, err
}
dSha256Hash = converter.BinToHex(dSha256Hash)
mrklSlice = append(mrklSlice, dSha256Hash)
}
}
if len(mrklSlice) == 0 {
mrklSlice = append(mrklSlice, []byte("0"))
}
return &Block{
Header: header,
Transactions: transactions,
MrklRoot: utils.MerkleTreeRoot(mrklSlice),
}, nil
}