-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathBlockchain.cpp
More file actions
227 lines (182 loc) · 5.73 KB
/
Blockchain.cpp
File metadata and controls
227 lines (182 loc) · 5.73 KB
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
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
#include "Blockchain.hpp"
using Utils::appendBytes;
using Utils::appendBytesArr;
Block::Block()
: myHash(NULL_HASH), prevHash(NULL_HASH) {}
Block::Block(const vector<Transaction> txs, Uint256 a_nonce, Uint256 a_soln)
: myHash(NULL_HASH), prevHash(NULL_HASH), txList(txs), nonce(a_nonce), soln(a_soln) {}
void Block::addTransaction(Transaction &tx) {
if(txList.size() < MAX_TX) {
txList.push_back(tx);
}
}
// Calculate the SHA-256 hash of the serialized block data.
// Result stored in myHash member
Sha256Hash Block::calcHash() {
// 1. Serialize block data
Bytes block;
// Header
appendBytesArr(block, prevHash.value, Sha256Hash::HASH_LEN);
appendBytes(block, Utils::Uint256ToBytes(nonce));
appendBytes(block, Utils::Uint256ToBytes(soln));
// Transactions
appendBytes(block, reward.serialize());
for(const auto &tx : txList) {
appendBytes(block, tx.serialize());
}
// 2. Compute hash
Sha256 blkHasher;
blkHasher.append(&block[0], block.size());
myHash = blkHasher.getHash();
return myHash;
}
Sha256Hash Block::getHash() const {
return myHash;
}
Sha256Hash Block::getPrevHash() const {
return prevHash;
}
void Block::setHash(Sha256Hash previousBlockHash) {
prevHash = previousBlockHash;
calcHash();
}
//____________________________________________________________________
//
const char GAIA_PRIV_STR[65] = "0000000000000000000000000000000000000000000000000000000000000002";
const char GAIA_PUB_STR[129] = "c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a";
Blockchain::Blockchain()
: GAIA_PRIV(GAIA_PRIV_STR), GAIA_PUB(GAIA_PUB_STR) {}
Blockchain::Blockchain(vector<Block> blockList)
: GAIA_PRIV(GAIA_PRIV_STR), GAIA_PUB(GAIA_PUB_STR), blocks(blockList) {}
bool Blockchain::addBlock(Block &block) {
// 1. Add link to chain
block.setHash(getTop()->getHash());
// 2. Validate block
if(isValidBlock(block)) {
blocks.push_back(block);
} else {
return false;
}
return true;
}
bool Blockchain::isValidBlock(const Block &block) const {
using std::cout;
using std::endl;
// Block Size
if(block.txList.size() > Block::MAX_TX) {
return false;
}
// 1. Verify transactions
for(const auto &tx : block.txList) {
// In order of computational cost
if(tx.amount <= 0 ) {
// This tx should just be ejected from the block instead of
// invalidating the block.
cout << "~~ BLOCK VALIDATION: empty tx from " + Utils::abridgeBytes(tx.fromKey.toBytes()) << endl;
return false;
}
// Verify signature
if(!tx.verify(tx.signature)) {
cout << "~~ BLOCK VALIDATION: failed signature verification." << endl;
return false;
}
// Verify balance
int bal = getAddressBalance(tx.fromKey);
//cout << "BAL? " << (bal > 50) << endl;
//cout << "Calc'd balance: " << bal << ", " << Utils::abridgeBytes(tx.fromKey.toBytes()) << endl;
if(tx.amount > bal) {
//if(tx.amount <= getAddressBalance(tx.fromKey)) {
cout << "~~ BLOCK VALIDATION: insuff. funds in tx from " + Utils::abridgeBytes(tx.fromKey.toBytes()) << endl;
return false;
}
// @missing isValidAddress(tx.from );
}
// @missing validate proof of work
return true;
}
// Validate that each block correctly links to the previous.
// @param sigs: verify signature of each transaction
int Blockchain::checkChainIntegrity(bool sigs) const {
//std::unordered_map<PublicKey, int> balances;
vector<Block>::const_iterator it, prev;
// @fix check first block
for(it = blocks.begin(); it != blocks.end(); prev = it, ++it) {
// Validate block header
if(it->getPrevHash() != prev->getHash()) {
return false;
}
/*if(it->myHash != it->getHash()) {
valid = false;
}*/
// Validate block
// Check that all transactions are valid
// - this would only every be useful if downloading the blockchain
// validate_block();
if(sigs) {
;;
}
}
return true;
}
Block Blockchain::getBlock(size_t depth) const {
assert(depth < blocks.size());
return blocks[depth];
}
std::string printTx(Transaction &tx) {
std::stringstream ss;
using Utils::bytesToStr;
using std::endl;
ss << " ~~~ Tx Details ~~~ \n";
ss << "from:\t" << bytesToStr(tx.fromKey.toBytes());
ss << "\nto:\t" << bytesToStr(tx.toKey.toBytes());
ss << "\namnt:\t" << tx.amount;
ss << "\nsig:\t" << bytesToStr(tx.signature.toBytes());
ss << endl;
return ss.str();
}
// @fix design should not treat genesis as a special case
void Blockchain::genesis(const PublicKey &whale, const int supply) {
assert(chainIsEmpty());
Transaction genTx(GAIA_PUB, whale, supply);
genTx.sign(GAIA_PRIV.get());
Block genesisBlock;
genesisBlock.addTransaction(genTx);
genesisBlock.setHash(NULL_HASH);
blocks.push_back(genesisBlock);
std::cout << "Pushed genesis block." << std::endl;
}
int Blockchain::getAddressBalance(const PublicKey &address) const {
using std::cout;
using std::endl;
int deb = 0;
int cred = 0;
// 1. Add all sends
int count;
for(const auto &block : blocks) {
for(const auto &tx : block.txList) {
if(tx.fromKey == address) {
deb += tx.amount;
}
if(tx.toKey == address) {
cred += tx.amount;
}
}
}
return cred - deb;
}
bool Blockchain::chainIsEmpty() const {
/*if(getTop() == blocks.begin()) {
return true;
}*/
return getTop() == blocks.begin();
}
vector<Block>::const_iterator Blockchain::getTop() const {
vector<Block>::const_iterator last = blocks.end();
if(blocks.size() > 0)
--last;
return last;
}
// @fix GAIA
//const PublicKey Blockchain::GAIA_PUB("79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8");
//const PrivateKey Blockchain::GAIA_PRIV("0000000000000000000000000000000000000000000000000000000000000001");
//const Uint256 dummy("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDBAAEDCE6AF48A03BBFD25E8CD0364141");