Skip to content

Commit 08cbfc7

Browse files
committedFeb 7, 2017
Day 3: 区块的构造
1 parent 81524fe commit 08cbfc7

File tree

4 files changed

+108
-3
lines changed

4 files changed

+108
-3
lines changed
 

‎src/main/kotlin/mbc/core/Block.kt

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package mbc.core
2+
3+
import mbc.util.CryptoUtil
4+
import org.joda.time.DateTime
5+
6+
/**
7+
* 区块(Block)类,包含了区块高度(height),上一个区块哈希值(parentHash),旷工账户地址(minerAddress),交易列表(transactions)和时间戳(time)。
8+
*/
9+
class Block(val height: Long, val parentHash: ByteArray, val minerAddress: String, val transactions: List<Transaction>,
10+
val time: DateTime) {
11+
12+
/**
13+
* 区块(Block)的哈希值(KECCAK-256)
14+
*/
15+
val hash: ByteArray
16+
get() = CryptoUtil.hashBlock(this)
17+
18+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
package mbc.core
2+
3+
import mbc.core.TransactionExecutor.applyTrx
4+
import org.joda.time.DateTime
5+
6+
/**
7+
* 区块链(BlockChain)管理类,负责区块的生成、发布、计算等功能。
8+
*/
9+
class BlockChain(val minerAddress: String) {
10+
11+
/**
12+
* 构造新的区块,要素信息为:区块高度(height),父区块的哈希值(parentHash), 交易记录(transactions),时间戳(time)
13+
*/
14+
fun createNewBlock(parent: Block, transactions: List<Transaction>): Block {
15+
val block = Block(parent.height + 1, parent.hash, minerAddress, transactions, DateTime())
16+
17+
for (trx in transactions) {
18+
applyTrx(trx)
19+
}
20+
21+
return block
22+
}
23+
}

‎src/main/kotlin/mbc/util/CryptoUtil.kt

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
package mbc.util
22

3+
import mbc.core.Block
34
import mbc.core.Transaction
45
import org.spongycastle.jce.provider.BouncyCastleProvider
56
import org.spongycastle.util.encoders.Hex
7+
import java.nio.ByteBuffer
68
import java.security.*
79
import java.security.Security.insertProviderAt
810
import java.security.spec.ECGenParameterSpec
@@ -46,7 +48,7 @@ class CryptoUtil {
4648
fun signTransaction(trx: Transaction, privateKey: PrivateKey): ByteArray {
4749
val signer = Signature.getInstance("SHA256withECDSA")
4850
signer.initSign(privateKey)
49-
val msgToSign = getTransactionContentToSign(trx)
51+
val msgToSign = encodeTransaction(trx)
5052
signer.update(msgToSign)
5153
return signer.sign()
5254
}
@@ -58,13 +60,38 @@ class CryptoUtil {
5860
val signer = Signature.getInstance("SHA256withECDSA")
5961
signer.initVerify(trx.publicKey)
6062

61-
signer.update(getTransactionContentToSign(trx))
63+
signer.update(encodeTransaction(trx))
6264
return signer.verify(signature)
6365
}
6466

65-
private fun getTransactionContentToSign(
67+
/**
68+
* 运算区块的哈希值。
69+
*/
70+
fun hashBlock(block: Block): ByteArray {
71+
val digest = MessageDigest.getInstance("KECCAK-256", "SC")
72+
digest.update(encodeBlock(block))
73+
return digest.digest()
74+
}
75+
76+
/**
77+
* 序列化交易(Transaction)。当前实现非常简单,后期会改成以太坊的RLP协议。
78+
*/
79+
private fun encodeTransaction(
6680
trx: Transaction) = (trx.senderAddress + trx.receiverAddress + trx.amount.toString() + trx.time.millis.toString()).toByteArray()
6781

82+
/**
83+
* 序列化区块(Block)。当前实现非常简单,后期会改成以太坊的RLP协议。
84+
*/
85+
private fun encodeBlock(block: Block): ByteArray {
86+
val byteBuffer = ByteBuffer.allocate(1024)
87+
byteBuffer.put(block.minerAddress.toByteArray())
88+
byteBuffer.put(block.time.millis.toString().toByteArray())
89+
block.transactions.map { byteBuffer.put(encodeTransaction(it)) }
90+
91+
byteBuffer.flip()
92+
return byteBuffer.array()
93+
}
94+
6895
}
6996

7097
}

‎src/test/kotlin/mbc/core/BlockChainTest.kt

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,4 +115,41 @@ class BlockChainTest {
115115
assert(trx.isValid)
116116
}
117117

118+
/**
119+
* 构造新的区块
120+
*/
121+
@Test fun createBlockTest() {
122+
// 初始化Alice账户
123+
val kp1 = generateKeyPair() ?: return
124+
val alice = Account(kp1.public)
125+
126+
// 初始化Bob账户
127+
val kp2 = generateKeyPair() ?: return
128+
val bob = Account(kp2.public)
129+
130+
// 初始金额为200
131+
addAmount(alice.address, 200)
132+
addAmount(bob.address, 200)
133+
134+
// Alice向Bob转账100
135+
val trx = Transaction(alice.address, bob.address, 100, DateTime(), kp1.public)
136+
// Alice用私钥签名
137+
trx.sign(kp1.private)
138+
139+
// 初始化矿工Charlie账户
140+
val kp3 = generateKeyPair() ?: return
141+
val charlie = Account(kp3.public)
142+
143+
// 构造原始区块(高度为0)
144+
val genesisBlock = Block(0, ByteArray(0), "1234567890123456789012345678901234567890", emptyList(), DateTime(2017,2,1,0,0))
145+
146+
// 构造新的区块
147+
val blockChain = BlockChain(charlie.address)
148+
blockChain.createNewBlock(genesisBlock, listOf(trx))
149+
150+
// 查询余额是否正确
151+
assert(alice.balance == 100L)
152+
assert(bob.balance == 300L)
153+
}
154+
118155
}

0 commit comments

Comments
 (0)
Please sign in to comment.