@@ -2,18 +2,24 @@ package mbc.core
2
2
3
3
import mbc.core.TransactionExecutor.addAmount
4
4
import mbc.core.TransactionExecutor.applyTrx
5
+ import mbc.miner.BlockMiner
6
+ import mbc.util.CryptoUtil
5
7
import mbc.util.CryptoUtil.Companion.generateKeyPair
6
- import mbc.util.CryptoUtil.Companion.signTransaction
8
+ import mbc.util.CryptoUtil.Companion.sha256
7
9
import mbc.util.CryptoUtil.Companion.verifyTransactionSignature
8
10
import org.joda.time.DateTime
9
11
import org.junit.Before
10
12
import org.junit.Test
11
13
import org.spongycastle.jce.provider.BouncyCastleProvider
14
+ import org.spongycastle.util.encoders.Hex
12
15
import java.math.BigInteger
13
- import java.security.spec.ECGenParameterSpec
16
+ import java.nio.ByteBuffer
14
17
import java.security.KeyPairGenerator
15
18
import java.security.Security
16
- import java.security.Signature;
19
+ import java.security.Signature
20
+ import java.security.spec.ECGenParameterSpec
21
+ import kotlin.test.assertEquals
22
+ import kotlin.test.assertNotEquals
17
23
18
24
19
25
class BlockChainTest {
@@ -141,7 +147,8 @@ class BlockChainTest {
141
147
val charlie = Account (kp3.public)
142
148
143
149
// 构造原始区块(高度为0)
144
- val genesisBlock = Block (0 , ByteArray (0 ), " 1234567890123456789012345678901234567890" , emptyList(), DateTime (2017 ,2 ,1 ,0 ,0 ))
150
+ val genesisBlock = Block (0 , ByteArray (0 ), " 1234567890123456789012345678901234567890" , emptyList(),
151
+ DateTime (2017 , 2 , 1 , 0 , 0 ))
145
152
146
153
// 构造新的区块
147
154
val blockChain = BlockChain (charlie.address)
@@ -152,4 +159,127 @@ class BlockChainTest {
152
159
assert (bob.balance == 300L )
153
160
}
154
161
162
+ /* *
163
+ * 挖矿算法测试。
164
+ */
165
+ @Test fun mineAlgorithmTest () {
166
+ val ver: Int = 1
167
+ val parentHash = " 000000000000000117c80378b8da0e33559b5997f2ad55e2f7d18ec1975b9717"
168
+ val merkleRoot = " 871714dcbae6c8193a2bb9b2a69fe1c0440399f38d94b3a0f1b447275a29978a"
169
+ val time = 0x53058b35 // 2014-02-20 04:57:25
170
+ val difficulty = 0x1f00ffff // difficulty,比特币的最小(初始)难度为0x1d00ffff,为测试方便我们降低难度为0x1f00ffff
171
+
172
+ // 挖矿难度的算法:https://en.bitcoin.it/wiki/Difficulty
173
+ val exp = difficulty shr 24
174
+ val mant = difficulty and 0xffffff
175
+ val target = BigInteger .valueOf(mant.toLong()).multiply(BigInteger .valueOf(2 ).pow(8 * (exp - 3 )))
176
+ val targetStr = " %064x" .format(target)
177
+ println (" Target:$targetStr " )
178
+
179
+ var nonce = 0
180
+ while (nonce < 0x100000000 ) {
181
+
182
+ val headerBuffer = ByteBuffer .allocate(4 + 32 + 32 + 4 + 4 + 4 )
183
+ headerBuffer.put(ByteBuffer .allocate(4 ).putInt(ver).array()) // version
184
+ headerBuffer.put(Hex .decode(parentHash)) // parentHash
185
+ headerBuffer.put(Hex .decode(merkleRoot)) // merkleRoot
186
+ headerBuffer.put(ByteBuffer .allocate(4 ).putInt(time).array()) // time
187
+ headerBuffer.put(ByteBuffer .allocate(4 ).putInt(difficulty).array()) // difficulty(current difficulty)
188
+ headerBuffer.put(ByteBuffer .allocate(4 ).putInt(nonce).array()) // nonce
189
+
190
+ val header = headerBuffer.array()
191
+ val hit = Hex .toHexString(sha256(sha256(header)))
192
+ println (" $nonce : $hit " )
193
+
194
+ if (hit < targetStr) {
195
+ println (" Got Nonce : $nonce " )
196
+ println (" Got Hit : $hit " )
197
+ break
198
+ }
199
+ nonce + = 1
200
+ }
201
+ }
202
+
203
+ /* *
204
+ * 挖矿难度(Difficulty)运算测试。
205
+ */
206
+ @Test fun difficultyTest () {
207
+ val difficulty = BigInteger .valueOf(0x0404cbL ).multiply(BigInteger .valueOf(2 ).pow(8 * (0x1b - 3 )))
208
+ assertEquals(difficulty.toString(16 ), " 404cb000000000000000000000000000000000000000000000000" )
209
+ }
210
+
211
+ /* *
212
+ * Merkle Root Hash测试。
213
+ */
214
+ @Test fun merkleTest () {
215
+ // 初始化Alice账户
216
+ val kp1 = generateKeyPair() ? : return
217
+ val alice = Account (kp1.public)
218
+
219
+ // 初始化Bob账户
220
+ val kp2 = generateKeyPair() ? : return
221
+ val bob = Account (kp2.public)
222
+
223
+ // Alice向Bob转账100
224
+ val trx1 = Transaction (alice.address, bob.address, 100 , DateTime (), kp1.public)
225
+
226
+ // Alice用私钥签名
227
+ val signature = trx1.sign(kp1.private)
228
+
229
+ // Alice向Bob转账50
230
+ val trx2 = Transaction (alice.address, bob.address, 50 , DateTime (), kp1.public)
231
+
232
+ // Alice用私钥签名
233
+ val signature2 = trx2.sign(kp1.private)
234
+
235
+ val merkleRoot = CryptoUtil .merkleRoot(listOf (trx1, trx2))
236
+ println (Hex .toHexString(merkleRoot))
237
+ }
238
+
239
+ /* *
240
+ * 挖矿
241
+ */
242
+ @Test fun mineBlockTest () {
243
+ // 初始化Alice账户
244
+ val kp1 = generateKeyPair() ? : return
245
+ val alice = Account (kp1.public)
246
+
247
+ // 初始化Bob账户
248
+ val kp2 = generateKeyPair() ? : return
249
+ val bob = Account (kp2.public)
250
+
251
+ // 初始金额为200
252
+ addAmount(alice.address, 200 )
253
+ addAmount(bob.address, 200 )
254
+
255
+ // Alice向Bob转账100
256
+ val trx = Transaction (alice.address, bob.address, 100 , DateTime (), kp1.public)
257
+ // Alice用私钥签名
258
+ trx.sign(kp1.private)
259
+
260
+ // 初始化矿工Charlie账户
261
+ val kp3 = generateKeyPair() ? : return
262
+ val charlie = Account (kp3.public)
263
+
264
+ // 构造原始区块(高度为0)
265
+ val genesisBlock = Block (0 , ByteArray (0 ), " 1234567890123456789012345678901234567890" , emptyList(),
266
+ DateTime (2017 , 2 , 1 , 0 , 0 ))
267
+
268
+ // 构造新的区块
269
+ val blockChain = BlockChain (charlie.address)
270
+ val block = blockChain.createNewBlock(genesisBlock, listOf (trx))
271
+
272
+ // 查询余额是否正确
273
+ assert (alice.balance == 100L )
274
+ assert (bob.balance == 300L )
275
+
276
+ val mineResult = BlockMiner .mine(block)
277
+ block.difficulty = mineResult.target
278
+ block.nonce = mineResult.nonce
279
+
280
+ println (" Block nonce: ${block.nonce} " )
281
+ assertNotEquals(block.difficulty, 0 )
282
+ assertNotEquals(block.nonce, 0 )
283
+ }
284
+
155
285
}
0 commit comments