├── .gitignore
├── LICENSE
├── README.md
├── block
├── pom.xml
└── src
│ ├── main
│ ├── java
│ │ └── com
│ │ │ └── magiccube
│ │ │ └── blockchain
│ │ │ ├── ApplicationContextProvider.java
│ │ │ ├── MagicCubeBlockchainApplication.java
│ │ │ ├── block
│ │ │ ├── Block.java
│ │ │ ├── BlockBody.java
│ │ │ ├── BlockHeader.java
│ │ │ ├── Instruction.java
│ │ │ ├── InstructionBase.java
│ │ │ ├── InstructionReverse.java
│ │ │ ├── Operation.java
│ │ │ ├── PairKey.java
│ │ │ ├── check
│ │ │ │ ├── BlockChecker.java
│ │ │ │ ├── CheckerManager.java
│ │ │ │ └── local
│ │ │ │ │ └── DbBlockChecker.java
│ │ │ ├── db
│ │ │ │ ├── DbInitConfig.java
│ │ │ │ ├── DbStore.java
│ │ │ │ ├── LevelDbStoreImpl.java
│ │ │ │ └── RocksDbStoreImpl.java
│ │ │ ├── m
│ │ │ │ ├── MerkleHash.java
│ │ │ │ ├── MerkleNode.java
│ │ │ │ ├── MerkleProofHash.java
│ │ │ │ ├── MerkleTree.java
│ │ │ │ └── Test.java
│ │ │ └── merkle
│ │ │ │ └── MerkleTree.java
│ │ │ ├── common
│ │ │ ├── AppId.java
│ │ │ ├── CommonUtil.java
│ │ │ ├── Constants.java
│ │ │ ├── FastJsonUtil.java
│ │ │ ├── PermissionType.java
│ │ │ ├── Sha256.java
│ │ │ ├── SwaggerConfig.java
│ │ │ ├── TrustSDK.java
│ │ │ ├── algorithm
│ │ │ │ ├── AESAlgorithm.java
│ │ │ │ ├── Base58Algorithm.java
│ │ │ │ ├── BaseAlgorithm.java
│ │ │ │ ├── DESAlgorithm.java
│ │ │ │ └── ECDSAAlgorithm.java
│ │ │ ├── exception
│ │ │ │ ├── ErrorNum.java
│ │ │ │ └── TrustSDKException.java
│ │ │ └── timer
│ │ │ │ └── TimerManager.java
│ │ │ ├── core
│ │ │ ├── bean
│ │ │ │ ├── BaseData.java
│ │ │ │ ├── Member.java
│ │ │ │ ├── MemberData.java
│ │ │ │ ├── Permission.java
│ │ │ │ ├── PermissionData.java
│ │ │ │ ├── ResultCode.java
│ │ │ │ └── ResultGenerator.java
│ │ │ ├── controller
│ │ │ │ ├── BlockController.java
│ │ │ │ ├── InstructionController.java
│ │ │ │ └── PairKeyController.java
│ │ │ ├── event
│ │ │ │ ├── AddBlockEvent.java
│ │ │ │ ├── ClientRequestEvent.java
│ │ │ │ ├── DbSyncEvent.java
│ │ │ │ └── NodesConnectedEvent.java
│ │ │ ├── manager
│ │ │ │ ├── DbBlockGenerator.java
│ │ │ │ ├── DbBlockManager.java
│ │ │ │ ├── MessageManager.java
│ │ │ │ ├── PermissionManager.java
│ │ │ │ └── SyncManager.java
│ │ │ ├── model
│ │ │ │ ├── MessageEntity.java
│ │ │ │ ├── SyncEntity.java
│ │ │ │ ├── base
│ │ │ │ │ └── BaseEntity.java
│ │ │ │ └── convert
│ │ │ │ │ └── ConvertTableName.java
│ │ │ ├── repository
│ │ │ │ ├── BaseRepository.java
│ │ │ │ ├── MessageRepository.java
│ │ │ │ └── SyncRepository.java
│ │ │ ├── requestbody
│ │ │ │ ├── BlockRequestBody.java
│ │ │ │ └── InstructionBody.java
│ │ │ ├── resthttp
│ │ │ │ └── RestTemplateConfig.java
│ │ │ ├── service
│ │ │ │ ├── BlockService.java
│ │ │ │ ├── InstructionService.java
│ │ │ │ └── PairKeyService.java
│ │ │ ├── sqlite
│ │ │ │ ├── SqliteManager.java
│ │ │ │ └── config
│ │ │ │ │ ├── DataSourceConfiguration.java
│ │ │ │ │ ├── JpaConfiguration.java
│ │ │ │ │ ├── ModelMetaData.java
│ │ │ │ │ ├── SQLiteDialect.java
│ │ │ │ │ ├── SQLiteMetadataBuilderInitializer.java
│ │ │ │ │ └── identity
│ │ │ │ │ └── SQLiteDialectIdentityColumnSupport.java
│ │ │ └── sqlparser
│ │ │ │ ├── AbstractSqlParser.java
│ │ │ │ ├── InstructionParser.java
│ │ │ │ ├── InstructionParserImpl.java
│ │ │ │ └── MessageSqlParser.java
│ │ │ └── socket
│ │ │ ├── base
│ │ │ ├── AbstractAioHandler.java
│ │ │ ├── AbstractBlockHandler.java
│ │ │ └── HandlerInterface.java
│ │ │ ├── body
│ │ │ ├── BaseBody.java
│ │ │ ├── BlockHash.java
│ │ │ ├── HeartBeatBody.java
│ │ │ ├── RpcBlockBody.java
│ │ │ ├── RpcCheckBlockBody.java
│ │ │ ├── RpcNextBlockBody.java
│ │ │ ├── RpcSimpleBlockBody.java
│ │ │ └── VoteBody.java
│ │ │ ├── client
│ │ │ ├── BlockClientAioHandler.java
│ │ │ ├── BlockClientAioListener.java
│ │ │ ├── BlockGeneratedListener.java
│ │ │ ├── ClientContextConfig.java
│ │ │ ├── ClientStarter.java
│ │ │ └── PacketSender.java
│ │ │ ├── common
│ │ │ └── Const.java
│ │ │ ├── distruptor
│ │ │ ├── DisruptorClientConsumer.java
│ │ │ ├── DisruptorClientHandler.java
│ │ │ ├── DisruptorConfig.java
│ │ │ ├── DisruptorProducer.java
│ │ │ ├── DisruptorServerConsumer.java
│ │ │ ├── DisruptorServerHandler.java
│ │ │ └── base
│ │ │ │ ├── BaseEvent.java
│ │ │ │ ├── BaseEventFactory.java
│ │ │ │ ├── MessageConsumer.java
│ │ │ │ └── MessageProducer.java
│ │ │ ├── handler
│ │ │ ├── client
│ │ │ │ ├── FetchBlockResponseHandler.java
│ │ │ │ ├── NextBlockResponseHandler.java
│ │ │ │ └── TotalBlockInfoResponseHandler.java
│ │ │ └── server
│ │ │ │ ├── FetchBlockRequestHandler.java
│ │ │ │ ├── GenerateBlockRequestHandler.java
│ │ │ │ ├── GenerateCompleteRequestHandler.java
│ │ │ │ ├── HeartBeatHandler.java
│ │ │ │ ├── NextBlockRequestHandler.java
│ │ │ │ ├── PbftVoteHandler.java
│ │ │ │ └── TotalBlockInfoRequestHandler.java
│ │ │ ├── packet
│ │ │ ├── BlockPacket.java
│ │ │ ├── NextBlockPacketBuilder.java
│ │ │ ├── PacketBuilder.java
│ │ │ └── PacketType.java
│ │ │ ├── pbft
│ │ │ ├── VoteType.java
│ │ │ ├── event
│ │ │ │ ├── MsgCommitEvent.java
│ │ │ │ └── MsgPrepareEvent.java
│ │ │ ├── listener
│ │ │ │ ├── CommitEventListener.java
│ │ │ │ └── PrepareEventListener.java
│ │ │ ├── msg
│ │ │ │ ├── VoteMsg.java
│ │ │ │ └── VotePreMsg.java
│ │ │ └── queue
│ │ │ │ ├── AbstractVoteMsgQueue.java
│ │ │ │ ├── BaseMsgQueue.java
│ │ │ │ ├── CommitMsgQueue.java
│ │ │ │ ├── MsgQueueManager.java
│ │ │ │ ├── NextBlockQueue.java
│ │ │ │ ├── PreMsgQueue.java
│ │ │ │ └── PrepareMsgQueue.java
│ │ │ └── server
│ │ │ ├── BlockServerAioHandler.java
│ │ │ ├── BlockServerAioListener.java
│ │ │ └── BlockServerStarter.java
│ └── resources
│ │ ├── application.copy.yml
│ │ └── application.yml
│ └── test
│ └── java
│ └── com
│ └── magiccube
│ └── blockchain
│ └── MagicCubeBlockchainApplicationTests.java
├── magiccubevm.iml
├── manager
├── pom.xml
└── src
│ ├── main
│ ├── java
│ │ └── com
│ │ │ └── magiccube
│ │ │ └── blockmanager
│ │ │ ├── McBlockchainManagerApplication.java
│ │ │ ├── bean
│ │ │ ├── BaseData.java
│ │ │ ├── MemberData.java
│ │ │ └── PermissionData.java
│ │ │ ├── constant
│ │ │ └── PermissionType.java
│ │ │ ├── controller
│ │ │ ├── MemberController.java
│ │ │ └── PermissionController.java
│ │ │ ├── manager
│ │ │ ├── MemberGroupManager.java
│ │ │ ├── MemberManager.java
│ │ │ └── PermissionManager.java
│ │ │ ├── model
│ │ │ ├── Member.java
│ │ │ ├── MemberGroup.java
│ │ │ ├── Permission.java
│ │ │ └── base
│ │ │ │ └── BaseEntity.java
│ │ │ └── repository
│ │ │ ├── MemberGroupRepository.java
│ │ │ ├── MemberRepository.java
│ │ │ └── PermissionRepository.java
│ └── resources
│ │ ├── application-local.yml
│ │ ├── application-prod.yml
│ │ └── application.yml
│ └── test
│ └── java
│ └── com
│ └── magiccube
│ └── blockmanager
│ └── McBlockchainManagerApplicationTests.java
└── pom.xml
/.gitignore:
--------------------------------------------------------------------------------
1 | # Compiled class file
2 | *.class
3 |
4 | # Log file
5 | *.log
6 |
7 | # BlueJ files
8 | *.ctxt
9 |
10 | # Mobile Tools for Java (J2ME)
11 | .mtj.tmp/
12 |
13 | .mvn
14 | mvnw
15 | mvnw.cmd
16 | log
17 |
18 | # Package Files #
19 | *.jar
20 | *.war
21 | *.nar
22 | *.ear
23 | *.zip
24 | *.tar.gz
25 | *.rar
26 |
27 | target
28 | .classpath
29 | .settings
30 | .project
31 | bin
32 |
33 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
34 | hs_err_pid*
35 | .vscode
36 | .idea
37 | .idea/misc.xml
38 | *.iml
39 | .DS_Store
40 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2018 Magic Cube
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/block/src/main/java/com/magiccube/blockchain/ApplicationContextProvider.java:
--------------------------------------------------------------------------------
1 | package com.magiccube.blockchain;
2 |
3 | import org.springframework.beans.BeansException;
4 | import org.springframework.context.ApplicationContext;
5 | import org.springframework.context.ApplicationContextAware;
6 | import org.springframework.context.ApplicationEvent;
7 | import org.springframework.stereotype.Component;
8 |
9 | @Component
10 | public class ApplicationContextProvider implements ApplicationContextAware {
11 | private static ApplicationContext context;
12 |
13 | public static ApplicationContext getApplicationContext() {
14 | return context;
15 | }
16 |
17 | @Override
18 | public void setApplicationContext(ApplicationContext ac)
19 | throws BeansException {
20 | context = ac;
21 | }
22 |
23 | public static T getBean(Class tClass) {
24 | return context.getBean(tClass);
25 | }
26 |
27 | public static T getBean(String name, Class tClass) {
28 | return context.getBean(name, tClass);
29 | }
30 |
31 | public static void publishEvent(ApplicationEvent event) {
32 | context.publishEvent(event);
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/block/src/main/java/com/magiccube/blockchain/MagicCubeBlockchainApplication.java:
--------------------------------------------------------------------------------
1 | package com.magiccube.blockchain;
2 |
3 | import org.springframework.boot.SpringApplication;
4 | import org.springframework.boot.autoconfigure.SpringBootApplication;
5 | import org.springframework.scheduling.annotation.EnableAsync;
6 | import org.springframework.scheduling.annotation.EnableScheduling;
7 |
8 | @SpringBootApplication
9 | @EnableScheduling
10 | @EnableAsync
11 | public class MagicCubeBlockchainApplication{
12 |
13 | public static void main(String[] args) {
14 | SpringApplication.run(MagicCubeBlockchainApplication.class, args);
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/block/src/main/java/com/magiccube/blockchain/block/Block.java:
--------------------------------------------------------------------------------
1 | package com.magiccube.blockchain.block;
2 |
3 | import cn.hutool.crypto.digest.DigestUtil;
4 |
5 | public class Block {
6 | /**
7 | * 区块头
8 | */
9 | private BlockHeader blockHeader;
10 | /**
11 | * 区块body
12 | */
13 | private BlockBody blockBody;
14 | /**
15 | * 该区块的hash
16 | */
17 | private String hash;
18 |
19 | /**
20 | * 根据该区块所有属性计算sha256
21 | * @return
22 | * sha256hex
23 | */
24 | private String calculateHash() {
25 | return DigestUtil.sha256Hex(
26 | blockHeader.toString() + blockBody.toString()
27 | );
28 | }
29 |
30 | public BlockHeader getBlockHeader() {
31 | return blockHeader;
32 | }
33 |
34 | public void setBlockHeader(BlockHeader blockHeader) {
35 | this.blockHeader = blockHeader;
36 | }
37 |
38 | public BlockBody getBlockBody() {
39 | return blockBody;
40 | }
41 |
42 | public void setBlockBody(BlockBody blockBody) {
43 | this.blockBody = blockBody;
44 | }
45 |
46 | public String getHash() {
47 | return hash;
48 | }
49 |
50 | public void setHash(String hash) {
51 | this.hash = hash;
52 | }
53 |
54 | @Override
55 | public String toString() {
56 | return "Block{" +
57 | "blockHeader=" + blockHeader +
58 | ", blockBody=" + blockBody +
59 | ", hash='" + hash + '\'' +
60 | '}';
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/block/src/main/java/com/magiccube/blockchain/block/BlockBody.java:
--------------------------------------------------------------------------------
1 | package com.magiccube.blockchain.block;
2 |
3 | import java.util.List;
4 |
5 | /**
6 | * 区块body,里面存放交易的数组
7 | */
8 | public class BlockBody {
9 | private List instructions;
10 |
11 | @Override
12 | public String toString() {
13 | return "BlockBody{" +
14 | "instructions=" + instructions +
15 | '}';
16 | }
17 |
18 | public List getInstructions() {
19 | return instructions;
20 | }
21 |
22 | public void setInstructions(List instructions) {
23 | this.instructions = instructions;
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/block/src/main/java/com/magiccube/blockchain/block/BlockHeader.java:
--------------------------------------------------------------------------------
1 | package com.magiccube.blockchain.block;
2 |
3 | import java.util.List;
4 |
5 | /**
6 | * 区块头
7 | */
8 | public class BlockHeader {
9 | /**
10 | * 版本号
11 | */
12 | private int version;
13 | /**
14 | * 上一区块的hash
15 | */
16 | private String hashPreviousBlock;
17 | /**
18 | * merkle tree根节点hash
19 | */
20 | private String hashMerkleRoot;
21 | /**
22 | * 生成该区块的公钥
23 | */
24 | private String publicKey;
25 | /**
26 | * 区块的序号
27 | */
28 | private int number;
29 | /**
30 | * 时间戳
31 | */
32 | private long timeStamp;
33 | /**
34 | * 32位随机数
35 | */
36 | private long nonce;
37 | /**
38 | * 该区块里每条交易信息的hash集合,按顺序来的,通过该hash集合能算出根节点hash
39 | */
40 | private List hashList;
41 |
42 | @Override
43 | public String toString() {
44 | return "BlockHeader{" +
45 | "version=" + version +
46 | ", hashPreviousBlock='" + hashPreviousBlock + '\'' +
47 | ", hashMerkleRoot='" + hashMerkleRoot + '\'' +
48 | ", publicKey='" + publicKey + '\'' +
49 | ", number=" + number +
50 | ", timeStamp=" + timeStamp +
51 | ", nonce=" + nonce +
52 | ", hashList=" + hashList +
53 | '}';
54 | }
55 |
56 | public int getVersion() {
57 | return version;
58 | }
59 |
60 | public void setVersion(int version) {
61 | this.version = version;
62 | }
63 |
64 | public String getHashPreviousBlock() {
65 | return hashPreviousBlock;
66 | }
67 |
68 | public void setHashPreviousBlock(String hashPreviousBlock) {
69 | this.hashPreviousBlock = hashPreviousBlock;
70 | }
71 |
72 | public String getHashMerkleRoot() {
73 | return hashMerkleRoot;
74 | }
75 |
76 | public void setHashMerkleRoot(String hashMerkleRoot) {
77 | this.hashMerkleRoot = hashMerkleRoot;
78 | }
79 |
80 | public String getPublicKey() {
81 | return publicKey;
82 | }
83 |
84 | public void setPublicKey(String publicKey) {
85 | this.publicKey = publicKey;
86 | }
87 |
88 | public int getNumber() {
89 | return number;
90 | }
91 |
92 | public void setNumber(int number) {
93 | this.number = number;
94 | }
95 |
96 | public long getTimeStamp() {
97 | return timeStamp;
98 | }
99 |
100 | public void setTimeStamp(long timeStamp) {
101 | this.timeStamp = timeStamp;
102 | }
103 |
104 | public long getNonce() {
105 | return nonce;
106 | }
107 |
108 | public void setNonce(long nonce) {
109 | this.nonce = nonce;
110 | }
111 |
112 | public List getHashList() {
113 | return hashList;
114 | }
115 |
116 | public void setHashList(List hashList) {
117 | this.hashList = hashList;
118 | }
119 | }
120 |
--------------------------------------------------------------------------------
/block/src/main/java/com/magiccube/blockchain/block/Instruction.java:
--------------------------------------------------------------------------------
1 | package com.magiccube.blockchain.block;
2 |
3 | /**
4 | * 区块body内一条指令
5 | */
6 | public class Instruction extends InstructionBase {
7 | /**
8 | * 新的内容
9 | */
10 | private String json;
11 | /**
12 | * 时间戳
13 | */
14 | private Long timeStamp;
15 | /**
16 | * 操作人的公钥
17 | */
18 | private String publicKey;
19 | /**
20 | * 签名
21 | */
22 | private String sign;
23 | /**
24 | * 该操作的hash
25 | */
26 | private String hash;
27 |
28 |
29 | public String getJson() {
30 | return json;
31 | }
32 |
33 | public void setJson(String json) {
34 | this.json = json;
35 | }
36 |
37 | public String getPublicKey() {
38 | return publicKey;
39 | }
40 |
41 | public void setPublicKey(String publicKey) {
42 | this.publicKey = publicKey;
43 | }
44 |
45 | public Long getTimeStamp() {
46 | return timeStamp;
47 | }
48 |
49 | public void setTimeStamp(Long timeStamp) {
50 | this.timeStamp = timeStamp;
51 | }
52 |
53 | public String getSign() {
54 | return sign;
55 | }
56 |
57 | public void setSign(String sign) {
58 | this.sign = sign;
59 | }
60 |
61 | public String getHash() {
62 | return hash;
63 | }
64 |
65 | public void setHash(String hash) {
66 | this.hash = hash;
67 | }
68 |
69 | @Override
70 | public String toString() {
71 | return "Instruction{" +
72 | "json='" + json + '\'' +
73 | ", timeStamp=" + timeStamp +
74 | ", publicKey='" + publicKey + '\'' +
75 | ", sign='" + sign + '\'' +
76 | ", hash='" + hash + '\'' +
77 | '}';
78 | }
79 | }
80 |
--------------------------------------------------------------------------------
/block/src/main/java/com/magiccube/blockchain/block/InstructionBase.java:
--------------------------------------------------------------------------------
1 | package com.magiccube.blockchain.block;
2 |
3 | /**
4 | * blockBody内一条指令的基础属性
5 | */
6 | public class InstructionBase {
7 | /**
8 | * 指令的操作,增删改(1,-1,2)
9 | */
10 | private byte operation;
11 | /**
12 | * 操作的表名
13 | */
14 | private String table;
15 | /**
16 | * 最终要执行入库的json内容
17 | */
18 | private String oldJson;
19 | /**
20 | * 业务id,sql语句中where需要该Id
21 | */
22 | private String instructionId;
23 |
24 | public byte getOperation() {
25 | return operation;
26 | }
27 |
28 | public void setOperation(byte operation) {
29 | this.operation = operation;
30 | }
31 |
32 | public String getTable() {
33 | return table;
34 | }
35 |
36 | public void setTable(String table) {
37 | this.table = table;
38 | }
39 |
40 | public String getOldJson() {
41 | return oldJson;
42 | }
43 |
44 | public void setOldJson(String oldJson) {
45 | this.oldJson = oldJson;
46 | }
47 |
48 | public String getInstructionId() {
49 | return instructionId;
50 | }
51 |
52 | public void setInstructionId(String instructionId) {
53 | this.instructionId = instructionId;
54 | }
55 |
56 | @Override
57 | public String toString() {
58 | return "InstructionReverse{" +
59 | "operation=" + operation +
60 | ", table='" + table + '\'' +
61 | ", oldJson='" + oldJson + '\'' +
62 | ", instructionId='" + instructionId + '\'' +
63 | '}';
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/block/src/main/java/com/magiccube/blockchain/block/InstructionReverse.java:
--------------------------------------------------------------------------------
1 | package com.magiccube.blockchain.block;
2 |
3 | /**
4 | * 一条指令用来回滚时所用
5 | */
6 | public class InstructionReverse extends InstructionBase {
7 |
8 | }
9 |
--------------------------------------------------------------------------------
/block/src/main/java/com/magiccube/blockchain/block/Operation.java:
--------------------------------------------------------------------------------
1 | package com.magiccube.blockchain.block;
2 |
3 |
4 | public interface Operation {
5 | byte ADD = 1;
6 | byte DELETE = -1;
7 | byte UPDATE = 2;
8 |
9 | }
10 |
--------------------------------------------------------------------------------
/block/src/main/java/com/magiccube/blockchain/block/PairKey.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Project Name:trustsql_sdk
3 | * File Name:PairKey.java
4 | * Package Name:com.tencent.trustsql.sdk.bean
5 | * Date:Jul 26, 201710:27:04 AM
6 | * Copyright (c) 2017, Tencent All Rights Reserved.
7 | */
8 |
9 | package com.magiccube.blockchain.block;
10 |
11 | /**
12 | * ClassName:PairKey
13 | * Date: Jul 26, 2017 10:27:04 AM
14 | * @author Rony
15 | * @since JDK 1.7
16 | */
17 | public class PairKey {
18 |
19 | private String publicKey;
20 | private String privateKey;
21 |
22 | public String getPublicKey() {
23 | return publicKey;
24 | }
25 |
26 | public void setPublicKey(String publicKey) {
27 | this.publicKey = publicKey;
28 | }
29 |
30 | public String getPrivateKey() {
31 | return privateKey;
32 | }
33 |
34 | public void setPrivateKey(String privateKey) {
35 | this.privateKey = privateKey;
36 | }
37 |
38 | }
39 |
40 |
--------------------------------------------------------------------------------
/block/src/main/java/com/magiccube/blockchain/block/check/BlockChecker.java:
--------------------------------------------------------------------------------
1 | package com.magiccube.blockchain.block.check;
2 |
3 | import com.magiccube.blockchain.block.Block;
4 |
5 | /**
6 | * 区块校验
7 | */
8 | public interface BlockChecker {
9 | /**
10 | * 比较目标区块和自己本地的区块num大小
11 | * @param block
12 | * 被比较的区块
13 | * @return
14 | * 本地与目标区块的差值
15 | */
16 | int checkNum(Block block);
17 |
18 | /**
19 | * 校验区块内操作的权限是否合法
20 | * @param block
21 | * block
22 | * @return
23 | * 大于0合法
24 | */
25 | int checkPermission(Block block);
26 |
27 | /**
28 | * 校验hash,包括prevHash、内部hash(merkle tree root hash)
29 | * @param block
30 | * block
31 | * @return
32 | * 大于0合法
33 | */
34 | int checkHash(Block block);
35 |
36 | /**
37 | * 校验生成时间
38 | * @param block block
39 | * @return block
40 | */
41 | int checkTime(Block block);
42 |
43 | /**
44 | * 校验签名
45 | * @param block block
46 | * @return block
47 | */
48 | int checkSign(Block block);
49 |
50 | /**
51 | * 校验block,包括签名、hash、关联关系
52 | * @param block
53 | * @return
54 | */
55 | public String checkBlock(Block block);
56 |
57 | }
58 |
--------------------------------------------------------------------------------
/block/src/main/java/com/magiccube/blockchain/block/check/CheckerManager.java:
--------------------------------------------------------------------------------
1 | package com.magiccube.blockchain.block.check;
2 |
3 | import com.magiccube.blockchain.block.Block;
4 | import com.magiccube.blockchain.socket.body.RpcCheckBlockBody;
5 | import org.springframework.stereotype.Component;
6 |
7 | import javax.annotation.Resource;
8 |
9 | /**
10 | * 区块校验
11 | */
12 | @Component
13 | public class CheckerManager {
14 | @Resource
15 | private BlockChecker blockChecker;
16 |
17 | /**
18 | * 基本校验
19 | * @param block block
20 | * @return 校验结果
21 | */
22 | public RpcCheckBlockBody check(Block block) {
23 | int code= blockChecker.checkSign(block);
24 | if (code != 0) {
25 | return new RpcCheckBlockBody(-1, "block的签名不合法");
26 | }
27 |
28 | int number = blockChecker.checkNum(block);
29 | if (number != 0) {
30 | return new RpcCheckBlockBody(-1, "block的number不合法");
31 | }
32 | int time = blockChecker.checkTime(block);
33 | if (time != 0) {
34 | return new RpcCheckBlockBody(-4, "block的时间错误");
35 | }
36 | int hash = blockChecker.checkHash(block);
37 | if (hash != 0) {
38 | return new RpcCheckBlockBody(-3, "hash校验不通过");
39 | }
40 | int permission = blockChecker.checkPermission(block);
41 | if (permission != 0) {
42 | return new RpcCheckBlockBody(-2, "没有表的操作权限");
43 | }
44 |
45 | return new RpcCheckBlockBody(0, "OK", block);
46 | }
47 |
48 | }
49 |
--------------------------------------------------------------------------------
/block/src/main/java/com/magiccube/blockchain/block/check/local/DbBlockChecker.java:
--------------------------------------------------------------------------------
1 | package com.magiccube.blockchain.block.check.local;
2 |
3 | import cn.hutool.core.util.StrUtil;
4 | import com.magiccube.blockchain.block.Block;
5 | import com.magiccube.blockchain.block.check.BlockChecker;
6 | import com.magiccube.blockchain.common.Sha256;
7 | import com.magiccube.blockchain.common.exception.TrustSDKException;
8 | import com.magiccube.blockchain.core.manager.DbBlockManager;
9 | import com.magiccube.blockchain.core.manager.PermissionManager;
10 | import com.magiccube.blockchain.core.requestbody.BlockRequestBody;
11 | import com.magiccube.blockchain.core.service.BlockService;
12 |
13 | import org.springframework.stereotype.Component;
14 |
15 | import javax.annotation.Resource;
16 |
17 | /**
18 | * 使用本地存储的权限、Block信息对新来的block进行校验
19 | */
20 | @Component
21 | public class DbBlockChecker implements BlockChecker {
22 | @Resource
23 | private DbBlockManager dbBlockManager;
24 | @Resource
25 | private PermissionManager permissionManager;
26 |
27 | @Resource
28 | private BlockService blockService;
29 |
30 | @Override
31 | public int checkNum(Block block) {
32 | Block localBlock = getLastBlock();
33 | int localNum = 0;
34 | if (localBlock != null) {
35 | localNum = localBlock.getBlockHeader().getNumber();
36 | }
37 | //本地区块+1等于新来的区块时才同意
38 | if (localNum + 1 == block.getBlockHeader().getNumber()) {
39 | //同意生成区块
40 | return 0;
41 | }
42 |
43 | //拒绝
44 | return -1;
45 | }
46 |
47 | @Override
48 | public int checkPermission(Block block) {
49 | //校验对表的操作权限
50 | return permissionManager.checkPermission(block) ? 0 : -1;
51 | }
52 |
53 | @Override
54 | public int checkHash(Block block) {
55 | Block localLast = getLastBlock();
56 | //创世块可以,或者新块的prev等于本地的last hash也可以
57 | if (localLast == null && block.getBlockHeader().getHashPreviousBlock() == null) {
58 | return 0;
59 | }
60 | if (localLast != null && StrUtil.equals(localLast.getHash(), block.getBlockHeader().getHashPreviousBlock())) {
61 | return 0;
62 | }
63 | return -1;
64 | }
65 |
66 | @Override
67 | public int checkTime(Block block) {
68 | Block localBlock = getLastBlock();
69 | //新区块的生成时间比本地的还小
70 | if (localBlock != null && block.getBlockHeader().getTimeStamp() <= localBlock.getBlockHeader().getTimeStamp()) {
71 | //拒绝
72 | return -1;
73 | }
74 | return 0;
75 | }
76 |
77 | @Override
78 | public int checkSign(Block block) {
79 | if(!checkBlockHashSign(block)) {
80 | return -1;
81 | }
82 | return 0;
83 | }
84 |
85 | private Block getLastBlock() {
86 | return dbBlockManager.getLastBlock();
87 | }
88 |
89 | public String checkBlock(Block block) {
90 | if(!checkBlockHashSign(block)) return block.getHash();
91 |
92 | String preHash = block.getBlockHeader().getHashPreviousBlock();
93 | if(preHash == null) return null;
94 |
95 | Block preBlock = dbBlockManager.getBlockByHash(preHash);
96 | if(preBlock == null) return block.getHash();
97 |
98 | int localNum = preBlock.getBlockHeader().getNumber();
99 | //当前区块+1等于下一个区块时才同意
100 | if (localNum + 1 != block.getBlockHeader().getNumber()) {
101 | return block.getHash();
102 | }
103 | if(block.getBlockHeader().getTimeStamp() <= preBlock.getBlockHeader().getTimeStamp()) {
104 | return block.getHash();
105 | }
106 |
107 |
108 | return null;
109 | }
110 |
111 | /**
112 | * 检测区块签名及hash是否符合
113 | * @param block
114 | * @return
115 | */
116 | private boolean checkBlockHashSign(Block block) {
117 | BlockRequestBody blockRequestBody = new BlockRequestBody();
118 | blockRequestBody.setBlockBody(block.getBlockBody());
119 | blockRequestBody.setPublicKey(block.getBlockHeader().getPublicKey());
120 | try {
121 | if(blockService.check(blockRequestBody) != null) return false;
122 | } catch (TrustSDKException e) {
123 | return false;
124 | }
125 |
126 | String hash = Sha256.sha256(block.getBlockHeader().toString() + block.getBlockBody().toString());
127 | if(!StrUtil.equals(block.getHash(),hash)) return false;
128 |
129 | return true;
130 | }
131 |
132 | }
133 |
--------------------------------------------------------------------------------
/block/src/main/java/com/magiccube/blockchain/block/db/DbInitConfig.java:
--------------------------------------------------------------------------------
1 | package com.magiccube.blockchain.block.db;
2 |
3 | import org.iq80.leveldb.DB;
4 | import org.iq80.leveldb.impl.Iq80DBFactory;
5 | import org.rocksdb.Options;
6 | import org.rocksdb.RocksDB;
7 | import org.rocksdb.RocksDBException;
8 | import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
9 | import org.springframework.context.annotation.Bean;
10 | import org.springframework.context.annotation.Configuration;
11 |
12 | import java.io.File;
13 | import java.io.IOException;
14 |
15 | /**
16 | * 配置启用哪个db,部分Windows机器用不了rocksDB,可以选择levelDB
17 | */
18 | @Configuration
19 | public class DbInitConfig {
20 |
21 | @Bean
22 | @ConditionalOnProperty("db.rocksDB")
23 | public RocksDB rocksDB() {
24 | RocksDB.loadLibrary();
25 |
26 | Options options = new Options().setCreateIfMissing(true);
27 | try {
28 | return RocksDB.open(options, "./rocksDB");
29 | } catch (RocksDBException e) {
30 | e.printStackTrace();
31 | return null;
32 | }
33 | }
34 |
35 | @Bean
36 | @ConditionalOnProperty("db.levelDB")
37 | public DB levelDB() throws IOException {
38 | org.iq80.leveldb.Options options = new org.iq80.leveldb.Options();
39 | options.createIfMissing(true);
40 | return Iq80DBFactory.factory.open(new File("./levelDB"), options);
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/block/src/main/java/com/magiccube/blockchain/block/db/DbStore.java:
--------------------------------------------------------------------------------
1 | package com.magiccube.blockchain.block.db;
2 |
3 | /**
4 | * key-value型DB数据库操作接口
5 | */
6 | public interface DbStore {
7 | /**
8 | * 数据库key value
9 | *
10 | * @param key
11 | * key
12 | * @param value
13 | * value
14 | */
15 | void put(String key, String value);
16 |
17 | /**
18 | * get By Key
19 | *
20 | * @param key
21 | * key
22 | * @return value
23 | */
24 | String get(String key);
25 |
26 | /**
27 | * remove by key
28 | *
29 | * @param key
30 | * key
31 | */
32 | void remove(String key);
33 | }
34 |
--------------------------------------------------------------------------------
/block/src/main/java/com/magiccube/blockchain/block/db/LevelDbStoreImpl.java:
--------------------------------------------------------------------------------
1 | package com.magiccube.blockchain.block.db;
2 |
3 | import org.iq80.leveldb.DB;
4 | import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
5 | import org.springframework.stereotype.Component;
6 |
7 | import javax.annotation.Resource;
8 |
9 | import static org.iq80.leveldb.impl.Iq80DBFactory.asString;
10 | import static org.iq80.leveldb.impl.Iq80DBFactory.bytes;
11 |
12 | /**
13 | * levelDB
14 | *
15 | */
16 | @Component
17 | @ConditionalOnProperty("db.levelDB")
18 | public class LevelDbStoreImpl implements DbStore {
19 | @Resource
20 | private DB db;
21 |
22 | @Override
23 | public void put(String key, String value) {
24 | db.put(bytes(key), bytes(value));
25 | }
26 |
27 | @Override
28 | public String get(String key) {
29 | return asString(db.get(bytes(key)));
30 | }
31 |
32 | @Override
33 | public void remove(String key) {
34 | db.delete(bytes(key));
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/block/src/main/java/com/magiccube/blockchain/block/db/RocksDbStoreImpl.java:
--------------------------------------------------------------------------------
1 | package com.magiccube.blockchain.block.db;
2 |
3 | import com.magiccube.blockchain.socket.common.Const;
4 | import org.rocksdb.RocksDB;
5 | import org.rocksdb.RocksDBException;
6 | import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
7 | import org.springframework.stereotype.Component;
8 |
9 | import javax.annotation.Resource;
10 | import java.io.UnsupportedEncodingException;
11 |
12 | /**
13 | * rocksDB对于存储接口的实现
14 | */
15 | @Component
16 | @ConditionalOnProperty("db.rocksDB")
17 | public class RocksDbStoreImpl implements DbStore {
18 | @Resource
19 | private RocksDB rocksDB;
20 |
21 | @Override
22 | public void put(String key, String value) {
23 | try {
24 | rocksDB.put(key.getBytes(Const.CHARSET), value.getBytes(Const.CHARSET));
25 | } catch (RocksDBException | UnsupportedEncodingException e) {
26 | e.printStackTrace();
27 | }
28 | }
29 |
30 |
31 | @Override
32 | public String get(String key) {
33 | try {
34 | byte[] bytes = rocksDB.get(key.getBytes(Const.CHARSET));
35 | if (bytes != null) {
36 | return new String(bytes, Const.CHARSET);
37 | }
38 | return null;
39 | } catch (Exception e) {
40 | e.printStackTrace();
41 | return null;
42 | }
43 | }
44 |
45 | @Override
46 | public void remove(String key) {
47 | try {
48 | rocksDB.delete(rocksDB.get(key.getBytes(Const.CHARSET)));
49 | } catch (RocksDBException | UnsupportedEncodingException e) {
50 | e.printStackTrace();
51 | }
52 | }
53 |
54 | }
55 |
--------------------------------------------------------------------------------
/block/src/main/java/com/magiccube/blockchain/block/m/MerkleHash.java:
--------------------------------------------------------------------------------
1 | package com.magiccube.blockchain.block.m;
2 |
3 | import java.nio.charset.StandardCharsets;
4 | import java.security.MessageDigest;
5 | import java.security.NoSuchAlgorithmException;
6 | import java.util.Arrays;
7 | import java.util.Base64;
8 |
9 | public class MerkleHash {
10 |
11 | /**
12 | * Hash value as byte array.
13 | */
14 | private byte[] value;
15 |
16 | public MerkleHash() {
17 | }
18 |
19 | /**
20 | * Create a MerkleHash from an array of bytes.
21 | *
22 | * @param buffer of bytes
23 | * @return a MerkleHash
24 | */
25 | public static MerkleHash create(byte[] buffer) {
26 | MerkleHash hash = new MerkleHash();
27 | hash.computeHash(buffer);
28 | return hash;
29 | }
30 |
31 | /**
32 | * Create a MerkleHash from a string. The string needs
33 | * first to be transformed in a UTF8 sequence of bytes.
34 | * Used for leaf hashes.
35 | *
36 | * @param buffer string
37 | * @return a MerkleHash
38 | */
39 | public static MerkleHash create(String buffer) {
40 | return create(buffer.getBytes(StandardCharsets.UTF_8));
41 | }
42 |
43 | /**
44 | * Create a MerkleHash from two MerkleHashes by concatenation
45 | * of the byte arrays. Used for internal nodes.
46 | *
47 | * @param left subtree hash
48 | * @param right subtree hash
49 | * @return a MerkleHash
50 | */
51 | public static MerkleHash create(MerkleHash left, MerkleHash right) {
52 | return create(concatenate(left.getValue(), right.getValue()));
53 | }
54 |
55 | /**
56 | * Get the byte value of a MerkleHash.
57 | *
58 | * @return an array of bytes
59 | */
60 | public byte[] getValue() {
61 | return value;
62 | }
63 |
64 | /**
65 | * Compare the MerkleHash with a given byte array.
66 | *
67 | * @param hash as byte array
68 | * @return boolean
69 | */
70 | public boolean equals(byte[] hash) {
71 | return Arrays.equals(this.value, hash);
72 | }
73 |
74 | /**
75 | * Compare the MerkleHash with a given MerkleHash.
76 | *
77 | * @param hash as MerkleHash
78 | * @return boolean
79 | */
80 | public boolean equals(MerkleHash hash) {
81 | boolean result = false;
82 | if (hash != null) {
83 | result = Arrays.equals(this.value, hash.getValue());
84 | }
85 | return result;
86 | }
87 |
88 | @Override
89 | public int hashCode() {
90 | return Arrays.hashCode(value);
91 | }
92 |
93 | /**
94 | * Encode in Base64 the MerkleHash.
95 | *
96 | * @return the string encoding of MerkleHash.
97 | */
98 | @Override
99 | public String toString() {
100 | return Base64.getEncoder().encodeToString(this.value);
101 | }
102 |
103 | /**
104 | * Compute SHA256 hash of a byte array.
105 | *
106 | * @param buffer of bytes
107 | */
108 | private void computeHash(byte[] buffer) {
109 | try {
110 | MessageDigest digest = MessageDigest.getInstance("SHA-256");
111 | this.value = digest.digest(buffer);
112 | } catch (NoSuchAlgorithmException e) {
113 | e.printStackTrace();
114 | }
115 | }
116 |
117 | /**
118 | * Concatenate two array of bytes.
119 | *
120 | * @param a is the first array
121 | * @param b is the second array
122 | * @return a byte array
123 | */
124 | public static byte[] concatenate(byte[] a, byte[] b) {
125 | byte[] c = new byte[a.length + b.length];
126 | System.arraycopy(a, 0, c, 0, a.length);
127 | System.arraycopy(b, 0, c, a.length, b.length);
128 | return c;
129 | }
130 | }
131 |
--------------------------------------------------------------------------------
/block/src/main/java/com/magiccube/blockchain/block/m/MerkleNode.java:
--------------------------------------------------------------------------------
1 | package com.magiccube.blockchain.block.m;
2 |
3 | import java.security.InvalidParameterException;
4 | import java.util.Objects;
5 |
6 | public class MerkleNode {
7 | private MerkleHash hash;
8 | private MerkleNode leftNode;
9 | private MerkleNode rightNode;
10 | private MerkleNode parent;
11 |
12 |
13 | public MerkleNode() {
14 | }
15 |
16 | public MerkleNode(MerkleHash hash) {
17 | this.hash = hash;
18 | }
19 |
20 | public MerkleNode(MerkleNode left, MerkleNode right) {
21 | this.leftNode = left;
22 | this.rightNode = right;
23 | this.leftNode.parent = this;
24 | if (this.rightNode != null) this.rightNode.parent = this;
25 |
26 | this.computeHash();
27 | }
28 |
29 | public boolean isLeaf() {
30 | return this.leftNode == null && this.rightNode == null;
31 | }
32 |
33 | @Override
34 | public String toString() {
35 | return hash.toString();
36 | }
37 |
38 | public void setLeftNode(MerkleNode node) {
39 | if (node.hash == null) {
40 | throw new InvalidParameterException("Node hash must be initialized!");
41 | }
42 |
43 | this.leftNode = node;
44 | this.leftNode.parent = this;
45 |
46 | this.computeHash();
47 | }
48 |
49 | public void setRightNode(MerkleNode node) {
50 | if (node.hash == null) {
51 | throw new InvalidParameterException("Node hash must be initialized!");
52 | }
53 |
54 | this.rightNode = node;
55 | this.rightNode.parent = this;
56 |
57 | if (this.leftNode != null) {
58 | this.computeHash();
59 | }
60 | }
61 |
62 | public boolean canVerifyHash() {
63 | return (this.leftNode != null && this.rightNode != null) || (this.leftNode != null);
64 | }
65 |
66 | public boolean verifyHash() {
67 | if (this.leftNode == null && this.rightNode == null) return true;
68 | if (this.rightNode == null) return hash.equals(leftNode.hash);
69 |
70 | if (this.leftNode == null) {
71 | throw new InvalidParameterException("Left branch must be a node if right branch is a node!");
72 | }
73 |
74 | MerkleHash leftRightHash = MerkleHash.create(this.leftNode.hash, this.rightNode.hash);
75 | return hash.equals(leftRightHash);
76 | }
77 |
78 | public boolean equals(MerkleNode other) {
79 | return this.hash.equals(other.hash);
80 | }
81 |
82 | public MerkleHash getHash() {
83 | return hash;
84 | }
85 |
86 | public MerkleNode getParent() {
87 | return parent;
88 | }
89 |
90 | public MerkleNode getLeftNode() {
91 | return leftNode;
92 | }
93 |
94 | public MerkleNode getRightNode() {
95 | return rightNode;
96 | }
97 |
98 | public void computeHash() {
99 | if (this.rightNode == null) {
100 | this.hash = this.leftNode.hash;
101 | } else {
102 | this.hash = MerkleHash.create(MerkleHash.concatenate(
103 | this.leftNode.hash.getValue(), this.rightNode.hash.getValue()));
104 | }
105 |
106 | if (this.parent != null) {
107 | this.parent.computeHash();
108 | }
109 | }
110 |
111 | @Override
112 | public int hashCode() {
113 |
114 | return Objects.hash(hash, leftNode, rightNode, parent);
115 | }
116 | }
117 |
--------------------------------------------------------------------------------
/block/src/main/java/com/magiccube/blockchain/block/m/MerkleProofHash.java:
--------------------------------------------------------------------------------
1 | package com.magiccube.blockchain.block.m;
2 |
3 | public class MerkleProofHash {
4 | public enum Branch {
5 | LEFT,
6 | RIGHT,
7 | OLD_ROOT
8 | }
9 |
10 | public MerkleHash hash;
11 | public Branch direction;
12 |
13 | public MerkleProofHash(MerkleHash hash, Branch direction) {
14 | this.hash = hash;
15 | this.direction = direction;
16 | }
17 |
18 | public MerkleHash getHash() {
19 | return hash;
20 | }
21 |
22 | public Branch getDirection() {
23 | return direction;
24 | }
25 |
26 | @Override
27 | public String toString() {
28 | String hash = this.hash.toString();
29 | String direction = this.direction.toString();
30 | return hash.concat(" is ".concat(direction).concat(" Child"));
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/block/src/main/java/com/magiccube/blockchain/block/m/Test.java:
--------------------------------------------------------------------------------
1 | package com.magiccube.blockchain.block.m;
2 |
3 | import java.util.List;
4 |
5 | public class Test {
6 | public static void main(String[] args) {
7 |
8 | MerkleTree merkleTree = new MerkleTree();
9 | MerkleNode merkleNode0 = new MerkleNode(MerkleHash.create("a"));
10 | MerkleNode merkleNode1 = new MerkleNode(MerkleHash.create("b"));
11 | MerkleNode merkleNode2 = new MerkleNode(MerkleHash.create("c"));
12 | MerkleNode merkleNode3 = new MerkleNode(MerkleHash.create("d"));
13 |
14 | merkleTree.appendLeaf(merkleNode0);
15 | merkleTree.appendLeaf(merkleNode1);
16 | merkleTree.appendLeaf(merkleNode2);
17 | merkleTree.appendLeaf(merkleNode3);
18 | merkleTree.buildTree();
19 | System.out.println(merkleTree.getRoot().getHash());
20 | List hashes = merkleTree.auditProof(MerkleHash.create("a"));
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/block/src/main/java/com/magiccube/blockchain/block/merkle/MerkleTree.java:
--------------------------------------------------------------------------------
1 | package com.magiccube.blockchain.block.merkle;
2 |
3 | import cn.hutool.crypto.digest.DigestUtil;
4 |
5 | import java.util.ArrayList;
6 | import java.util.List;
7 |
8 | /**
9 | * merkle tree简单实现
10 | */
11 | public class MerkleTree {
12 | /**
13 | * transaction List
14 | */
15 | private List txList;
16 | /**
17 | * Merkle Root
18 | */
19 | private String root;
20 |
21 | /**
22 | * constructor
23 | *
24 | * @param txList
25 | * transaction List 交易List
26 | */
27 | public MerkleTree(List txList) {
28 | this.txList = txList;
29 | root = "";
30 | }
31 |
32 | /**
33 | * execute merkle_tree and set root.
34 | */
35 | public MerkleTree build() {
36 | List tempTxList = new ArrayList<>(this.txList);
37 |
38 | List newTxList = getNewTxList(tempTxList);
39 |
40 | while (newTxList.size() != 1) {
41 | newTxList = getNewTxList(newTxList);
42 | }
43 |
44 | this.root = newTxList.get(0);
45 | return this;
46 | }
47 |
48 | /**
49 | * return Node Hash List.
50 | *
51 | * @param tempTxList
52 | * list
53 | * @return
54 | * 某一层的左右节点相连hash
55 | */
56 | private List getNewTxList(List tempTxList) {
57 | List newTxList = new ArrayList<>();
58 | int index = 0;
59 | while (index < tempTxList.size()) {
60 | // left
61 | String left = tempTxList.get(index);
62 | index++;
63 | // right
64 | String right = "";
65 | if (index != tempTxList.size()) {
66 | right = tempTxList.get(index);
67 | }
68 | // sha2 hex value
69 | String sha2HexValue = DigestUtil.sha256Hex(left + right);
70 | newTxList.add(sha2HexValue);
71 | index++;
72 | }
73 |
74 | return newTxList;
75 | }
76 |
77 | /**
78 | * Get Root
79 | *
80 | * @return
81 | * 根节点hash
82 | */
83 | public String getRoot() {
84 | return this.root;
85 | }
86 |
87 | }
88 |
--------------------------------------------------------------------------------
/block/src/main/java/com/magiccube/blockchain/common/AppId.java:
--------------------------------------------------------------------------------
1 | package com.magiccube.blockchain.common;
2 |
3 | import org.springframework.beans.factory.annotation.Value;
4 | import org.springframework.stereotype.Component;
5 |
6 | import javax.annotation.PostConstruct;
7 |
8 | @Component
9 | public class AppId {
10 | /**
11 | * 节点的唯一标志
12 | */
13 | @Value("${appId}")
14 | private String appId;
15 | /**
16 | * 该客户的唯一标志
17 | */
18 | @Value("${name}")
19 | private String name;
20 |
21 | public static String value;
22 | public static String nameValue;
23 |
24 | @PostConstruct
25 | public void init() {
26 | value = appId;
27 | nameValue = name;
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/block/src/main/java/com/magiccube/blockchain/common/CommonUtil.java:
--------------------------------------------------------------------------------
1 | package com.magiccube.blockchain.common;
2 |
3 | import java.net.InetAddress;
4 | import java.net.NetworkInterface;
5 | import java.util.Enumeration;
6 | import java.util.UUID;
7 |
8 | public class CommonUtil {
9 | public static Long getNow() {
10 | return System.currentTimeMillis();
11 | }
12 |
13 | public static void main(String[] args) {
14 | InetAddress inetAddress = getLocalHostLANAddress();
15 | System.out.println(inetAddress.getHostName());
16 | }
17 |
18 | public static String getLocalIp() {
19 | InetAddress inetAddress = getLocalHostLANAddress();
20 | if (inetAddress != null) {
21 | return inetAddress.getHostAddress();
22 | }
23 | return null;
24 | }
25 |
26 | public static String generateUuid() {
27 | return UUID.randomUUID().toString();
28 | }
29 |
30 | /**
31 | * 获取本机ip地址
32 | */
33 | private static InetAddress getLocalHostLANAddress() {
34 | try {
35 | InetAddress candidateAddress = null;
36 | // 遍历所有的网络接口
37 | for (Enumeration ifaces = NetworkInterface.getNetworkInterfaces(); ifaces.hasMoreElements(); ) {
38 | NetworkInterface iface = (NetworkInterface) ifaces.nextElement();
39 | // 在所有的接口下再遍历IP
40 | for (Enumeration inetAddrs = iface.getInetAddresses(); inetAddrs.hasMoreElements(); ) {
41 | InetAddress inetAddr = (InetAddress) inetAddrs.nextElement();
42 | // 排除loopback类型地址
43 | if (!inetAddr.isLoopbackAddress()) {
44 | if (inetAddr.isSiteLocalAddress()) {
45 | // 如果是site-local地址,就是它了
46 | return inetAddr;
47 | } else if (candidateAddress == null) {
48 | // site-local类型的地址未被发现,先记录候选地址
49 | candidateAddress = inetAddr;
50 | }
51 | }
52 | }
53 | }
54 | if (candidateAddress != null) {
55 | return candidateAddress;
56 | }
57 | // 如果没有发现 non-loopback地址.只能用最次选的方案
58 | return InetAddress.getLocalHost();
59 | } catch (Exception e) {
60 | e.printStackTrace();
61 | }
62 | return null;
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/block/src/main/java/com/magiccube/blockchain/common/Constants.java:
--------------------------------------------------------------------------------
1 | package com.magiccube.blockchain.common;
2 |
3 | import java.math.BigInteger;
4 |
5 | public interface Constants {
6 |
7 | int PUBKEY_DIGEST_LENGTH = 90; // public key length
8 | int PRVKEY_DIGEST_LENGTH = 45; //private key length
9 | int ADDR_DIGEST_LENGTH = 35; // address length
10 | int SIGN_DIGEST_LENGTH = 98; // signature length
11 | int KEY_DES3_DIGEST_LENGTH = 24; // max size of key for DES3 encrypt
12 | int KEY_AES128_DIGEST_LENGTH = 16; // max size of key for AES128 encrypt
13 | int TRANSSQL_DIGEST_LENGTH = 8192; // max size of trans sql for TrustSQL
14 |
15 | String RANDOM_NUMBER_ALGORITHM = "SHA1PRNG";
16 | String RANDOM_NUMBER_ALGORITHM_PROVIDER = "SUN";
17 | BigInteger MAXPRIVATEKEY = new BigInteger("00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364140", 16);
18 |
19 | String INFO_SHARE_PUBKEY = "BC8s/4qEAvVl4Sv0LwQOWJcVU6Q5hBd+7LlJeEivVmUbdtwP4RTfN8x/G+muMhN8SrweyyVVMIcIrnMWoFqGfIA=";
20 |
21 | /**
22 | * 最后一个区块hash的key,value就是最后一个区块的hash
23 | */
24 | String KEY_LAST_BLOCK = "key_last_block";
25 | /**
26 | * 第一个区块hash的key,value就是第一个区块的hash
27 | */
28 | String KEY_FIRST_BLOCK = "key_first_block";
29 | /**
30 | * 区块hash与区块本身的key value映射,key的前缀,如{key_block_xxxxxxx -> blockJson}
31 | */
32 | String KEY_BLOCK_HASH_PREFIX = "key_block_";
33 |
34 | String KEY_REQUEST_PREFIX = "key_request_";
35 | /**
36 | * 保存区块的hash和下一区块hash,key为hash,value为下一区块hash
37 | */
38 | String KEY_BLOCK_NEXT_PREFIX = "key_next_";
39 | /**
40 | * 每个表的权限存储key
41 | */
42 | String KEY_PERMISSION = "key_permission_";
43 | }
44 |
45 |
--------------------------------------------------------------------------------
/block/src/main/java/com/magiccube/blockchain/common/FastJsonUtil.java:
--------------------------------------------------------------------------------
1 | package com.magiccube.blockchain.common;
2 |
3 | import com.alibaba.fastjson.JSON;
4 | import com.alibaba.fastjson.JSONObject;
5 | import com.alibaba.fastjson.serializer.JSONLibDataFormatSerializer;
6 | import com.alibaba.fastjson.serializer.SerializeConfig;
7 | import com.alibaba.fastjson.serializer.SerializerFeature;
8 |
9 | import java.util.List;
10 | import java.util.Map;
11 |
12 | public class FastJsonUtil {
13 | private static final SerializeConfig CONFIG;
14 |
15 | static {
16 | CONFIG = new SerializeConfig();
17 | CONFIG.put(java.util.Date.class, new JSONLibDataFormatSerializer()); // 使用和json-lib兼容的日期输出格式
18 | CONFIG.put(java.sql.Date.class, new JSONLibDataFormatSerializer()); // 使用和json-lib兼容的日期输出格式
19 | }
20 |
21 | private static final SerializerFeature[] FEATURES = {SerializerFeature.WriteMapNullValue, // 输出空置字段
22 | SerializerFeature.WriteNullListAsEmpty, // list字段如果为null,输出为[],而不是null
23 | SerializerFeature.WriteNullNumberAsZero, // 数值字段如果为null,输出为0,而不是null
24 | SerializerFeature.WriteNullBooleanAsFalse, // Boolean字段如果为null,输出为false,而不是null
25 | SerializerFeature.WriteNullStringAsEmpty // 字符类型字段如果为null,输出为"",而不是null
26 | };
27 |
28 |
29 | public static String toJSONString(Object object) {
30 | return JSON.toJSONString(object, CONFIG, FEATURES);
31 | }
32 |
33 | public static String toJSONNoFeatures(Object object) {
34 | return JSON.toJSONString(object, CONFIG);
35 | }
36 |
37 |
38 | public static Object toBean(String text) {
39 | return JSON.parse(text);
40 | }
41 |
42 | public static T toBean(String text, Class clazz) {
43 | return JSON.parseObject(text, clazz);
44 | }
45 |
46 | /**
47 | * 转换为数组
48 | */
49 | public static Object[] toArray(String text) {
50 | return toArray(text, null);
51 | }
52 |
53 | /**
54 | * 转换为数组
55 | */
56 | public static Object[] toArray(String text, Class clazz) {
57 | return JSON.parseArray(text, clazz).toArray();
58 | }
59 |
60 | /**
61 | * 转换为List
62 | */
63 | public static List toList(String text, Class clazz) {
64 | return JSON.parseArray(text, clazz);
65 | }
66 |
67 | /**
68 | * 将string转化为序列化的json字符串
69 | */
70 | public static Object textToJson(String text) {
71 | return JSON.parse(text);
72 | }
73 |
74 | /**
75 | * json字符串转化为map
76 | */
77 | public static Map stringToCollect(String s) {
78 | return JSONObject.parseObject(s);
79 | }
80 |
81 | /**
82 | * 将map转化为string
83 | */
84 | public static String collectToString(Map m) {
85 | return JSONObject.toJSONString(m);
86 | }
87 | }
88 |
--------------------------------------------------------------------------------
/block/src/main/java/com/magiccube/blockchain/common/PermissionType.java:
--------------------------------------------------------------------------------
1 | package com.magiccube.blockchain.common;
2 |
3 | /**
4 | * 对表的权限
5 | */
6 | public interface PermissionType {
7 | /**
8 | * 表的创建者
9 | */
10 | byte OWNER = 1;
11 | /**
12 | * 所有权限
13 | */
14 | byte ALL = 2;
15 | byte ADD = 3;
16 | byte UPDATE = 4;
17 | byte DELETE = 5;
18 | /**
19 | * 不可见
20 | */
21 | byte NONE = -1;
22 | }
23 |
--------------------------------------------------------------------------------
/block/src/main/java/com/magiccube/blockchain/common/Sha256.java:
--------------------------------------------------------------------------------
1 | package com.magiccube.blockchain.common;
2 |
3 | import cn.hutool.crypto.digest.DigestUtil;
4 |
5 | public class Sha256 {
6 | public static String sha256(String input) {
7 | return DigestUtil.sha256Hex(input);
8 | }
9 |
10 | }
11 |
--------------------------------------------------------------------------------
/block/src/main/java/com/magiccube/blockchain/common/algorithm/AESAlgorithm.java:
--------------------------------------------------------------------------------
1 | package com.magiccube.blockchain.common.algorithm;
2 |
3 | import javax.crypto.Cipher;
4 | import javax.crypto.spec.SecretKeySpec;
5 |
6 | public class AESAlgorithm {
7 |
8 | /**
9 | * aesEncode:aes 加密.
10 | *
11 | * @author Rony
12 | * @param key
13 | * 秘钥
14 | * @param data
15 | * 明文
16 | */
17 | public static byte[] aesEncode(byte[] key, byte[] data) throws Exception {
18 | Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
19 | SecretKeySpec secretKey = new SecretKeySpec(key, "AES");
20 | cipher.init(Cipher.ENCRYPT_MODE, secretKey);
21 | return cipher.doFinal(data);
22 | }
23 |
24 | /**
25 | * aesDecode: aes 解密.
26 | *
27 | * @author Rony
28 | * @param key key
29 | * @param encryptedText encryptedText
30 | * @return encryptedText
31 | * @throws Exception Exception
32 | * @since JDK 1.7
33 | */
34 | public static byte[] aesDecode(byte[] key, byte[] encryptedText) throws Exception {
35 | Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5PADDING");
36 | SecretKeySpec secretKey = new SecretKeySpec(key, "AES");
37 | cipher.init(Cipher.DECRYPT_MODE, secretKey);
38 | return cipher.doFinal(encryptedText);
39 | }
40 |
41 | }
42 |
--------------------------------------------------------------------------------
/block/src/main/java/com/magiccube/blockchain/common/algorithm/BaseAlgorithm.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Project Name:trustsql_sdk
3 | * File Name:BaseAlgoUtil.java
4 | * Package Name:com.tencent.trustsql.sdk.algo
5 | * Date:Jul 26, 20175:54:22 PM
6 | * Copyright (c) 2017, Tencent All Rights Reserved.
7 | *
8 | */
9 |
10 | package com.magiccube.blockchain.common.algorithm;
11 |
12 |
13 | import org.bouncycastle.jce.provider.BouncyCastleProvider;
14 |
15 | import java.security.MessageDigest;
16 | import java.security.Security;
17 |
18 | public class BaseAlgorithm {
19 |
20 | static {
21 | Security.addProvider(new BouncyCastleProvider());
22 | }
23 |
24 | /**
25 | * encode bytes
26 | *
27 | * @param algorithm algorithm
28 | * @param data data
29 | * @return byte[]
30 | */
31 | public static byte[] encode(String algorithm, byte[] data) {
32 | if (data == null) {
33 | return null;
34 | }
35 | try {
36 | MessageDigest messageDigest = MessageDigest.getInstance(algorithm);
37 | messageDigest.update(data);
38 | return messageDigest.digest();
39 | } catch (Exception e) {
40 | throw new RuntimeException(e);
41 | }
42 | }
43 |
44 | /**
45 | * encodeTwice bytes
46 | *
47 | * @param algorithm algorithm
48 | * @param data data
49 | * @return byte[]
50 | */
51 | protected static byte[] encodeTwice(String algorithm, byte[] data) {
52 | if (data == null) {
53 | return null;
54 | }
55 | try {
56 | MessageDigest messageDigest = MessageDigest.getInstance(algorithm);
57 | messageDigest.update(data);
58 | return messageDigest.digest(messageDigest.digest());
59 | } catch (Exception e) {
60 | throw new RuntimeException(e);
61 | }
62 | }
63 |
64 | }
65 |
--------------------------------------------------------------------------------
/block/src/main/java/com/magiccube/blockchain/common/algorithm/DESAlgorithm.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Project Name:trustsql_sdk
3 | * File Name:DESAlgoUtil2.java
4 | * Package Name:com.tencent.trustsql.sdk.algo
5 | * Date:Jul 28, 201710:38:59 AM
6 | * Copyright (c) 2017, NUCC All Rights Reserved.
7 | *
8 | */
9 |
10 | package com.magiccube.blockchain.common.algorithm;
11 |
12 | import javax.crypto.Cipher;
13 | import javax.crypto.SecretKeyFactory;
14 | import javax.crypto.spec.DESedeKeySpec;
15 | import java.security.Key;
16 |
17 | public class DESAlgorithm {
18 | /**
19 | * 密钥算法
20 | * */
21 | public static final String KEY_ALGORITHM = "DESede";
22 |
23 | /**
24 | * 加密/解密算法/工作模式/填充方式
25 | * */
26 | public static final String CIPHER_ALGORITHM = "DESede/ECB/PKCS5Padding";
27 |
28 | /**
29 | * 转换密钥
30 | *
31 | * @param key
32 | * 二进制密钥
33 | * @return Key 密钥
34 | * */
35 | public static Key toKey(byte[] key) throws Exception {
36 | // 实例化Des密钥
37 | DESedeKeySpec dks = new DESedeKeySpec(key);
38 | // 实例化密钥工厂
39 | SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(KEY_ALGORITHM);
40 | // 生成密钥
41 | return keyFactory.generateSecret(dks);
42 | }
43 |
44 | /**
45 | * 加密数据
46 | *
47 | * @param data
48 | * 待加密数据
49 | * @param key
50 | * 密钥
51 | * @return byte[] 加密后的数据
52 | * */
53 | public static byte[] encrypt(byte[] data, byte[] key) throws Exception {
54 | // 还原密钥
55 | Key k = toKey(key);
56 | // 实例化
57 | Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
58 | // 初始化,设置为加密模式
59 | cipher.init(Cipher.ENCRYPT_MODE, k);
60 | // 执行操作
61 | return cipher.doFinal(data);
62 | }
63 |
64 | /**
65 | * 解密数据
66 | *
67 | * @param data
68 | * 待解密数据
69 | * @param key
70 | * 密钥
71 | * @return byte[] 解密后的数据
72 | * */
73 | public static byte[] decrypt(byte[] data, byte[] key) throws Exception {
74 | // 欢迎密钥
75 | Key k = toKey(key);
76 | // 实例化
77 | Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
78 | // 初始化,设置为解密模式
79 | cipher.init(Cipher.DECRYPT_MODE, k);
80 | // 执行操作
81 | return cipher.doFinal(data);
82 | }
83 | }
84 |
85 |
--------------------------------------------------------------------------------
/block/src/main/java/com/magiccube/blockchain/common/exception/ErrorNum.java:
--------------------------------------------------------------------------------
1 |
2 | package com.magiccube.blockchain.common.exception;
3 |
4 | public enum ErrorNum {
5 |
6 | INVALID_PARAM_ERROR("001", "参数错误"),
7 | DES3_ENCRYPT_ERROR("002", "DES3加解密错误"),
8 | AES_ENCRYPT_ERROR("003", "AES加解密错误"),
9 | ECDSA_ENCRYPT_ERROR("004", "ECDSA加解密错误"),
10 | SIGN_ERROR("005", "签名错误"),
11 | GENERATE_SIGN_ERROR("006", "生成签名错误"),
12 | GENERATE_SQL_ERROR("007", "生成SQL错误"),
13 | VERIFY_SIGN_ERROR("008", "验证签名错误");
14 |
15 | private String retCode;
16 | private String retMsg;
17 |
18 | ErrorNum(String retCode, String retMsg) {
19 | this.retCode = retCode;
20 | this.retMsg = retMsg;
21 | }
22 |
23 | public String getRetCode() {
24 | return retCode;
25 | }
26 |
27 | public void setRetCode(String retCode) {
28 | this.retCode = retCode;
29 | }
30 |
31 | public String getRetMsg() {
32 | return retMsg;
33 | }
34 |
35 | public void setRetMsg(String retMsg) {
36 | this.retMsg = retMsg;
37 | }
38 | }
39 |
40 |
--------------------------------------------------------------------------------
/block/src/main/java/com/magiccube/blockchain/common/exception/TrustSDKException.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Project Name:trustsql_sdk
3 | * File Name:TrustSDKException.java
4 | * Package Name:com.tencent.trustsql.sdk.exception
5 | * Date:Jul 26, 201711:24:06 AM
6 | * Copyright (c) 2017, Tencent All Rights Reserved.
7 | *
8 | */
9 |
10 | package com.magiccube.blockchain.common.exception;
11 |
12 | import com.alibaba.fastjson.JSONObject;
13 |
14 | public class TrustSDKException extends Exception {
15 |
16 | private static final long serialVersionUID = -4214831807802264420L;
17 |
18 | protected String rtnCd;
19 | protected String rtnMsg;
20 |
21 | public TrustSDKException(String rtnCd, String rtnMsg) {
22 | super(rtnMsg);
23 | this.rtnCd = rtnCd;
24 | this.rtnMsg = rtnMsg;
25 | }
26 |
27 | public TrustSDKException(String rtnCd, String rtnMsg, Throwable t) {
28 | super(rtnMsg, t);
29 | this.rtnCd = rtnCd;
30 | this.rtnMsg = rtnMsg;
31 | }
32 |
33 | public String getRtnCd() {
34 | return rtnCd;
35 | }
36 |
37 | public void setRtnCd(String rtnCd) {
38 | this.rtnCd = rtnCd;
39 | }
40 |
41 | public String getRtnMsg() {
42 | return rtnMsg;
43 | }
44 |
45 | public void setRtnMsg(String rtnMsg) {
46 | this.rtnMsg = rtnMsg;
47 | }
48 |
49 | @Override
50 | public String toString() {
51 | return JSONObject.toJSONString(this);
52 | }
53 | }
54 |
55 |
--------------------------------------------------------------------------------
/block/src/main/java/com/magiccube/blockchain/common/timer/TimerManager.java:
--------------------------------------------------------------------------------
1 | package com.magiccube.blockchain.common.timer;
2 |
3 | import java.util.concurrent.Executors;
4 | import java.util.concurrent.ScheduledExecutorService;
5 | import java.util.concurrent.TimeUnit;
6 | import java.util.function.Supplier;
7 |
8 | public class TimerManager {
9 |
10 | private volatile static ScheduledExecutorService executorService = Executors.newScheduledThreadPool(3);
11 |
12 | public static void schedule(Supplier> action, long delay) {
13 | executorService.schedule(new Runnable() {
14 | @Override
15 | public void run() {
16 | action.get();
17 | }
18 | }, delay, TimeUnit.MILLISECONDS);
19 | }
20 |
21 | public static void scheduleAtFixedRate(Supplier> action, long initialDelay, long period) {
22 | executorService.scheduleAtFixedRate(new Runnable() {
23 | @Override
24 | public void run() {
25 | action.get();
26 | }
27 | }, initialDelay, period, TimeUnit.MILLISECONDS);
28 | }
29 |
30 | public static void scheduleWithFixedDelay(Supplier> action, long initialDelay, long period) {
31 | executorService.scheduleWithFixedDelay(new Runnable() {
32 | @Override
33 | public void run() {
34 | action.get();
35 | }
36 | }, initialDelay, period, TimeUnit.MILLISECONDS);
37 | }
38 |
39 |
40 | }
41 |
--------------------------------------------------------------------------------
/block/src/main/java/com/magiccube/blockchain/core/bean/BaseData.java:
--------------------------------------------------------------------------------
1 | package com.magiccube.blockchain.core.bean;
2 |
3 | public class BaseData {
4 | private int code;
5 | private String message;
6 | private Object data;
7 |
8 | @Override
9 | public String toString() {
10 | return "BaseData{" +
11 | "code=" + code +
12 | ", message='" + message + '\'' +
13 | ", data=" + data +
14 | '}';
15 | }
16 |
17 | public BaseData setCode(ResultCode resultCode) {
18 | this.code = resultCode.code;
19 | return this;
20 | }
21 |
22 | public int getCode() {
23 | return code;
24 | }
25 |
26 | public BaseData setCode(int code) {
27 | this.code = code;
28 | return this;
29 | }
30 |
31 | public String getMessage() {
32 | return message;
33 | }
34 |
35 | public BaseData setMessage(String message) {
36 | this.message = message;
37 | return this;
38 | }
39 |
40 | public Object getData() {
41 | return data;
42 | }
43 |
44 | public BaseData setData(Object data) {
45 | this.data = data;
46 | return this;
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/block/src/main/java/com/magiccube/blockchain/core/bean/Member.java:
--------------------------------------------------------------------------------
1 | package com.magiccube.blockchain.core.bean;
2 |
3 |
4 | import java.util.Date;
5 |
6 | /**
7 | * 联盟的成员
8 | */
9 | public class Member {
10 | /**
11 | * 成员id,用于校验该客户是否合法,客户端启动时需要带着该值。一个公司可能有多个appId,相当于多个服务器节点
12 | */
13 | private String appId;
14 | /**
15 | * 成员名
16 | */
17 | private String name;
18 | /**
19 | * ip(可不设置,由该成员客户端启动后自行检测)
20 | */
21 | private String ip;
22 |
23 | private Date createTime;
24 |
25 | private Date updateTime;
26 |
27 | @Override
28 | public String toString() {
29 | return "Member{" +
30 | "appId='" + appId + '\'' +
31 | ", name='" + name + '\'' +
32 | ", ip='" + ip + '\'' +
33 | '}';
34 | }
35 |
36 | public String getAppId() {
37 | return appId;
38 | }
39 |
40 | public void setAppId(String appId) {
41 | this.appId = appId;
42 | }
43 |
44 | public String getName() {
45 | return name;
46 | }
47 |
48 | public void setName(String name) {
49 | this.name = name;
50 | }
51 |
52 | public String getIp() {
53 | return ip;
54 | }
55 |
56 | public void setIp(String ip) {
57 | this.ip = ip;
58 | }
59 |
60 | }
61 |
--------------------------------------------------------------------------------
/block/src/main/java/com/magiccube/blockchain/core/bean/MemberData.java:
--------------------------------------------------------------------------------
1 | package com.magiccube.blockchain.core.bean;
2 |
3 | import java.util.List;
4 |
5 | public class MemberData {
6 | private int code;
7 | private String message;
8 | private List members;
9 |
10 | public int getCode() {
11 | return code;
12 | }
13 |
14 | public void setCode(int code) {
15 | this.code = code;
16 | }
17 |
18 | public String getMessage() {
19 | return message;
20 | }
21 |
22 | public void setMessage(String message) {
23 | this.message = message;
24 | }
25 |
26 | public List getMembers() {
27 | return members;
28 | }
29 |
30 | public void setMembers(List members) {
31 | this.members = members;
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/block/src/main/java/com/magiccube/blockchain/core/bean/Permission.java:
--------------------------------------------------------------------------------
1 | package com.magiccube.blockchain.core.bean;
2 |
3 | /**
4 | * 权限,主要存储各member对表的权限信息,如不可见、只能ADD,可以UPDATE、DELETE等等组合
5 | */
6 | public class Permission {
7 | /**
8 | * 哪张表
9 | */
10 | private String tableName;
11 | /**
12 | * 操作权限,见PermissionType类
13 | */
14 | private byte permissionType;
15 | /**
16 | * 公钥(账户的概念,能具体到某个member,为*则代表所有节点,不具体指定某个)
17 | */
18 | private String publicKey;
19 | /**
20 | * 该权限是归属于哪个group的。节点只需要获取自己group的权限信息,不需要知道别的group的
21 | */
22 | private String groupId;
23 |
24 | @Override
25 | public String toString() {
26 | return "Permission{" +
27 | "tableName='" + tableName + '\'' +
28 | ", permissionType=" + permissionType +
29 | ", publicKey='" + publicKey + '\'' +
30 | ", groupId='" + groupId + '\'' +
31 | '}';
32 | }
33 |
34 | public String getPublicKey() {
35 | return publicKey;
36 | }
37 |
38 | public void setPublicKey(String publicKey) {
39 | this.publicKey = publicKey;
40 | }
41 |
42 | public String getGroupId() {
43 | return groupId;
44 | }
45 |
46 | public void setGroupId(String groupId) {
47 | this.groupId = groupId;
48 | }
49 |
50 | public String getTableName() {
51 | return tableName;
52 | }
53 |
54 | public void setTableName(String tableName) {
55 | this.tableName = tableName;
56 | }
57 |
58 | public byte getPermissionType() {
59 | return permissionType;
60 | }
61 |
62 | public void setPermissionType(byte permissionType) {
63 | this.permissionType = permissionType;
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/block/src/main/java/com/magiccube/blockchain/core/bean/PermissionData.java:
--------------------------------------------------------------------------------
1 | package com.magiccube.blockchain.core.bean;
2 |
3 | import java.util.List;
4 |
5 | public class PermissionData extends BaseData {
6 | private List permissions;
7 |
8 | public List getPermissions() {
9 | return permissions;
10 | }
11 |
12 | public void setPermissions(List permissions) {
13 | this.permissions = permissions;
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/block/src/main/java/com/magiccube/blockchain/core/bean/ResultCode.java:
--------------------------------------------------------------------------------
1 | package com.magiccube.blockchain.core.bean;
2 |
3 |
4 | public enum ResultCode {
5 | //成功
6 | SUCCESS(200),
7 | //失败
8 | FAIL(400),
9 | //未认证(签名错误)
10 | UNAUTHORIZED(401),
11 | //没有登录
12 | NO_LOGIN(402),
13 | //没有权限
14 | NO_PERMISSION(403),
15 | //接口不存在
16 | NOT_FOUND(404),
17 | //用户状态异常、公司状态异常、产品状态异常
18 | STATE_ERROR(406),
19 | //服务器内部错误
20 | INTERNAL_SERVER_ERROR(500),
21 | //参数错误
22 | PARAMETER_ERROR(10001),
23 | //账号错误
24 | ACCOUNT_ERROR(20001),
25 | //登录失败
26 | LOGIN_FAIL_ERROR(20002);
27 |
28 |
29 | public int code;
30 |
31 | ResultCode(int code) {
32 | this.code = code;
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/block/src/main/java/com/magiccube/blockchain/core/bean/ResultGenerator.java:
--------------------------------------------------------------------------------
1 | package com.magiccube.blockchain.core.bean;
2 |
3 | public class ResultGenerator {
4 | private static final String DEFAULT_SUCCESS_MESSAGE = "SUCCESS";
5 |
6 | public static BaseData genSuccessResult() {
7 | return new BaseData()
8 | .setCode(ResultCode.SUCCESS)
9 | .setMessage(DEFAULT_SUCCESS_MESSAGE);
10 | }
11 |
12 | public static BaseData genSuccessResult(Object data) {
13 | return new BaseData()
14 | .setCode(ResultCode.SUCCESS)
15 | .setMessage(DEFAULT_SUCCESS_MESSAGE)
16 | .setData(data);
17 | }
18 |
19 | public static BaseData genFailResult(String message) {
20 | return new BaseData()
21 | .setCode(ResultCode.FAIL)
22 | .setMessage(message);
23 | }
24 |
25 | public static BaseData genFailResult(ResultCode resultCode, String message) {
26 | return new BaseData()
27 | .setCode(resultCode)
28 | .setMessage(message);
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/block/src/main/java/com/magiccube/blockchain/core/controller/InstructionController.java:
--------------------------------------------------------------------------------
1 | package com.magiccube.blockchain.core.controller;
2 |
3 | import com.magiccube.blockchain.core.bean.BaseData;
4 | import com.magiccube.blockchain.core.bean.ResultGenerator;
5 | import com.magiccube.blockchain.core.requestbody.InstructionBody;
6 | import com.magiccube.blockchain.core.service.InstructionService;
7 | import org.springframework.web.bind.annotation.PostMapping;
8 | import org.springframework.web.bind.annotation.RequestBody;
9 | import org.springframework.web.bind.annotation.RequestMapping;
10 | import org.springframework.web.bind.annotation.RestController;
11 | import springfox.documentation.annotations.ApiIgnore;
12 |
13 | import javax.annotation.Resource;
14 |
15 | /**
16 | * 区块body内单个指令的controller
17 | */
18 | @ApiIgnore
19 | @RestController
20 | @RequestMapping("/instruction")
21 | public class InstructionController {
22 | @Resource
23 | private InstructionService instructionService;
24 |
25 | /**
26 | * 构建一条指令,传入各必要参数
27 | * @param instructionBody instructionBody
28 | * @return
29 | * 用私钥签名后的指令
30 | */
31 | @PostMapping
32 | public BaseData build(@RequestBody InstructionBody instructionBody) throws Exception {
33 | if (!instructionService.checkKeyPair(instructionBody)) {
34 | return ResultGenerator.genFailResult("公私钥不是一对");
35 | }
36 | if (!instructionService.checkContent(instructionBody)) {
37 | return ResultGenerator.genFailResult("Delete和Update操作需要有id和json内容");
38 | }
39 | return ResultGenerator.genSuccessResult(instructionService.build(instructionBody));
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/block/src/main/java/com/magiccube/blockchain/core/controller/PairKeyController.java:
--------------------------------------------------------------------------------
1 | package com.magiccube.blockchain.core.controller;
2 |
3 | import com.magiccube.blockchain.common.exception.TrustSDKException;
4 | import com.magiccube.blockchain.core.bean.BaseData;
5 | import com.magiccube.blockchain.core.bean.ResultGenerator;
6 | import com.magiccube.blockchain.core.service.PairKeyService;
7 | import io.swagger.annotations.Api;
8 | import io.swagger.annotations.ApiOperation;
9 | import org.springframework.web.bind.annotation.GetMapping;
10 | import org.springframework.web.bind.annotation.RequestMapping;
11 | import org.springframework.web.bind.annotation.RestController;
12 |
13 | import javax.annotation.Resource;
14 |
15 | @Api(tags = "区块链接口", description = "公私钥接口")
16 | @RestController
17 | @RequestMapping("/pairKey")
18 | public class PairKeyController {
19 | @Resource
20 | private PairKeyService pairKeyService;
21 |
22 | /**
23 | * 生成公钥私钥
24 | */
25 | @ApiOperation(value = "区块链公私钥接口", notes = "生成区块链节点公私钥", httpMethod = "GET", response = BaseData.class)
26 | @GetMapping("/random")
27 | public BaseData generate() throws TrustSDKException {
28 | return ResultGenerator.genSuccessResult(pairKeyService.generate());
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/block/src/main/java/com/magiccube/blockchain/core/event/AddBlockEvent.java:
--------------------------------------------------------------------------------
1 | package com.magiccube.blockchain.core.event;
2 |
3 | import com.magiccube.blockchain.block.Block;
4 | import org.springframework.context.ApplicationEvent;
5 |
6 | /**
7 | * 确定生成block的Event(添加到rocksDB,执行sqlite语句,发布给其他节点)
8 | */
9 | public class AddBlockEvent extends ApplicationEvent {
10 | public AddBlockEvent(Block block) {
11 | super(block);
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/block/src/main/java/com/magiccube/blockchain/core/event/ClientRequestEvent.java:
--------------------------------------------------------------------------------
1 | package com.magiccube.blockchain.core.event;
2 |
3 | import com.magiccube.blockchain.socket.packet.BlockPacket;
4 | import org.springframework.context.ApplicationEvent;
5 |
6 | /**
7 | * 客户端对外发请求时会触发该Event
8 | */
9 | public class ClientRequestEvent extends ApplicationEvent {
10 | public ClientRequestEvent(BlockPacket blockPacket) {
11 | super(blockPacket);
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/block/src/main/java/com/magiccube/blockchain/core/event/DbSyncEvent.java:
--------------------------------------------------------------------------------
1 | package com.magiccube.blockchain.core.event;
2 |
3 | import org.springframework.context.ApplicationEvent;
4 |
5 | /**
6 | * 同步block到sqlite事件
7 | */
8 | public class DbSyncEvent extends ApplicationEvent {
9 | public DbSyncEvent(Object source) {
10 | super(source);
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/block/src/main/java/com/magiccube/blockchain/core/event/NodesConnectedEvent.java:
--------------------------------------------------------------------------------
1 | package com.magiccube.blockchain.core.event;
2 |
3 | import org.springframework.context.ApplicationEvent;
4 | import org.tio.core.ChannelContext;
5 |
6 | /**
7 | * 节点连接完成时会触发该Event
8 | */
9 | public class NodesConnectedEvent extends ApplicationEvent {
10 | private static final long serialVersionUID = 526755692642414178L;
11 |
12 | public NodesConnectedEvent(ChannelContext channelContext) {
13 | super(channelContext);
14 | }
15 |
16 | public ChannelContext getSource() {
17 | return (ChannelContext) source;
18 | }
19 |
20 | }
21 |
--------------------------------------------------------------------------------
/block/src/main/java/com/magiccube/blockchain/core/manager/DbBlockGenerator.java:
--------------------------------------------------------------------------------
1 | package com.magiccube.blockchain.core.manager;
2 |
3 | import com.magiccube.blockchain.ApplicationContextProvider;
4 | import com.magiccube.blockchain.block.Block;
5 | import com.magiccube.blockchain.block.check.CheckerManager;
6 | import com.magiccube.blockchain.block.db.DbStore;
7 | import com.magiccube.blockchain.common.Constants;
8 | import com.magiccube.blockchain.core.event.AddBlockEvent;
9 | import com.magiccube.blockchain.core.event.DbSyncEvent;
10 | import org.slf4j.Logger;
11 | import org.slf4j.LoggerFactory;
12 | import org.springframework.context.event.EventListener;
13 | import org.springframework.core.annotation.Order;
14 | import org.springframework.scheduling.annotation.Async;
15 | import org.springframework.stereotype.Service;
16 | import org.tio.utils.json.Json;
17 |
18 | import javax.annotation.Resource;
19 |
20 | /**
21 | * block的本地存储
22 | */
23 | @Service
24 | public class DbBlockGenerator {
25 | @Resource
26 | private DbStore dbStore;
27 | @Resource
28 | private CheckerManager checkerManager;
29 | private Logger logger = LoggerFactory.getLogger(getClass());
30 |
31 | /**
32 | * 数据库里添加一个新的区块
33 | *
34 | * @param addBlockEvent
35 | * addBlockEvent
36 | */
37 | @Order(1)
38 | @EventListener(AddBlockEvent.class)
39 | public synchronized void addBlock(AddBlockEvent addBlockEvent) {
40 | logger.info("开始生成本地block");
41 | Block block = (Block) addBlockEvent.getSource();
42 | String hash = block.getHash();
43 | //如果已经存在了,说明已经更新过该Block了
44 | if (dbStore.get(hash) != null) {
45 | return;
46 | }
47 | //校验区块
48 | if (checkerManager.check(block).getCode() != 0) {
49 | return;
50 | }
51 |
52 | //如果没有上一区块,说明该块就是创世块
53 | if (block.getBlockHeader().getHashPreviousBlock() == null) {
54 | dbStore.put(Constants.KEY_FIRST_BLOCK, hash);
55 | } else {
56 | //保存上一区块对该区块的key value映射
57 | dbStore.put(Constants.KEY_BLOCK_NEXT_PREFIX + block.getBlockHeader().getHashPreviousBlock(), hash);
58 | }
59 | //存入rocksDB
60 | dbStore.put(hash, Json.toJson(block));
61 | //设置最后一个block的key value
62 | dbStore.put(Constants.KEY_LAST_BLOCK, hash);
63 |
64 | logger.info("本地已生成新的Block");
65 |
66 | //同步到sqlite
67 | sqliteSync();
68 | }
69 |
70 | /**
71 | * sqlite根据block信息,执行sql
72 | */
73 | @Async
74 | public void sqliteSync() {
75 | //开始同步到sqlite
76 | ApplicationContextProvider.publishEvent(new DbSyncEvent(""));
77 | }
78 | }
79 |
--------------------------------------------------------------------------------
/block/src/main/java/com/magiccube/blockchain/core/manager/DbBlockManager.java:
--------------------------------------------------------------------------------
1 | package com.magiccube.blockchain.core.manager;
2 |
3 | import cn.hutool.core.util.StrUtil;
4 | import com.magiccube.blockchain.block.Block;
5 | import com.magiccube.blockchain.block.db.DbStore;
6 | import com.magiccube.blockchain.common.Constants;
7 | import com.magiccube.blockchain.common.FastJsonUtil;
8 | import org.springframework.stereotype.Service;
9 |
10 | import javax.annotation.Resource;
11 |
12 | @Service
13 | public class DbBlockManager {
14 | @Resource
15 | private DbStore dbStore;
16 |
17 | /**
18 | * 查找第一个区块
19 | *
20 | * @return 第一个Block
21 | */
22 | public Block getFirstBlock() {
23 | String firstBlockHash = dbStore.get(Constants.KEY_FIRST_BLOCK);
24 | if (StrUtil.isEmpty(firstBlockHash)) {
25 | return null;
26 | }
27 | return getBlockByHash(firstBlockHash);
28 | }
29 |
30 | /**
31 | * 获取最后一个区块信息
32 | *
33 | * @return 最后一个区块
34 | */
35 | public Block getLastBlock() {
36 | String lastBlockHash = dbStore.get(Constants.KEY_LAST_BLOCK);
37 | if (StrUtil.isEmpty(lastBlockHash)) {
38 | return null;
39 | }
40 | return getBlockByHash(lastBlockHash);
41 | }
42 |
43 | /**
44 | * 获取最后一个区块的hash
45 | *
46 | * @return hash
47 | */
48 | public String getLastBlockHash() {
49 | Block block = getLastBlock();
50 | if (block != null) {
51 | return block.getHash();
52 | }
53 | return null;
54 | }
55 |
56 | /**
57 | * 获取最后一个block的number
58 | * @return number
59 | */
60 | public int getLastBlockNumber() {
61 | Block block = getLastBlock();
62 | if (block != null) {
63 | return block.getBlockHeader().getNumber();
64 | }
65 | return 0;
66 | }
67 |
68 | /**
69 | * 获取某一个block的下一个Block
70 | *
71 | * @param block
72 | * block
73 | * @return block
74 | */
75 | public Block getNextBlock(Block block) {
76 | if (block == null) {
77 | return getFirstBlock();
78 | }
79 | String nextHash = dbStore.get(Constants.KEY_BLOCK_NEXT_PREFIX + block.getHash());
80 | if (nextHash == null) {
81 | return null;
82 | }
83 | return getBlockByHash(nextHash);
84 | }
85 |
86 | public Block getNextBlockByHash(String hash) {
87 | if (hash == null) {
88 | return getFirstBlock();
89 | }
90 | String nextHash = dbStore.get(Constants.KEY_BLOCK_NEXT_PREFIX + hash);
91 | if (nextHash == null) {
92 | return null;
93 | }
94 | return getBlockByHash(nextHash);
95 | }
96 |
97 | public Block getBlockByHash(String hash) {
98 | String blockJson = dbStore.get(hash);
99 | return FastJsonUtil.toBean(blockJson, Block.class);
100 | }
101 |
102 | }
103 |
--------------------------------------------------------------------------------
/block/src/main/java/com/magiccube/blockchain/core/manager/MessageManager.java:
--------------------------------------------------------------------------------
1 | package com.magiccube.blockchain.core.manager;
2 |
3 | import com.magiccube.blockchain.core.model.MessageEntity;
4 | import com.magiccube.blockchain.core.repository.MessageRepository;
5 | import org.springframework.stereotype.Component;
6 |
7 | import javax.annotation.Resource;
8 | import java.util.List;
9 | import java.util.stream.Collectors;
10 |
11 | @Component
12 | public class MessageManager {
13 | @Resource
14 | private MessageRepository messageRepository;
15 |
16 | public List findAll() {
17 | return messageRepository.findAll();
18 | }
19 |
20 | public List findAllContent() {
21 | return findAll().stream().map(MessageEntity::getContent).collect(Collectors.toList());
22 | }
23 |
24 | public MessageEntity findById(String id) {
25 | return messageRepository.findByMessageId(id);
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/block/src/main/java/com/magiccube/blockchain/core/manager/PermissionManager.java:
--------------------------------------------------------------------------------
1 | package com.magiccube.blockchain.core.manager;
2 |
3 | import com.magiccube.blockchain.block.Block;
4 | import com.magiccube.blockchain.block.Instruction;
5 | import com.magiccube.blockchain.common.PermissionType;
6 | import com.magiccube.blockchain.core.bean.Permission;
7 | import org.slf4j.Logger;
8 | import org.slf4j.LoggerFactory;
9 | import org.springframework.stereotype.Service;
10 |
11 | import java.util.*;
12 |
13 | /**
14 | * 对Permission信息的存储和使用
15 | */
16 | @Service
17 | public class PermissionManager {
18 | private Logger logger = LoggerFactory.getLogger(getClass());
19 |
20 | /**
21 | * 将权限信息常驻内存
22 | */
23 | public static final Map> PERMISSION_MAP = new HashMap<>();
24 |
25 | /**
26 | * 校验block内的所有指令的权限是否合法
27 | * @param block 区块
28 | * @return 合法
29 | */
30 | public boolean checkPermission(Block block) {
31 | List instructions = block.getBlockBody().getInstructions();
32 | return checkPermission(instructions);
33 | }
34 |
35 | public boolean checkPermission(List instructions) {
36 | for (Instruction instruction : instructions) {
37 | String publicKey = instruction.getPublicKey();
38 | String tableName = instruction.getTable();
39 | byte operation = instruction.getOperation();
40 | //TODO 这块要优化,循环次数太多,需要精简
41 | if (!checkOperation(publicKey, tableName, operation)) {
42 | return false;
43 | }
44 | }
45 | return true;
46 | }
47 |
48 |
49 | /**
50 | * 校验某用户对某表的某个操作是否有权限
51 | *
52 | * @param publicKey
53 | * 公钥
54 | * @param tableName
55 | * 表名
56 | * @param operation
57 | * 操作
58 | * @return 有权限true
59 | */
60 | private boolean checkOperation(String publicKey, String tableName, byte operation) {
61 | List permissionList = PERMISSION_MAP.get(tableName);
62 |
63 | Set userPermissionSet = new HashSet<>();
64 | for (Permission permission : permissionList) {
65 | //如果是不限用户的情况,取到该表的所有公开的权限
66 | if ("*".equals(permission.getPublicKey())) {
67 | userPermissionSet.add(permission.getPermissionType());
68 | } else {
69 | //找到该publicKey的所有权限
70 | if (publicKey.equals(permission.getPublicKey())) {
71 | userPermissionSet.add(permission.getPermissionType());
72 | }
73 | }
74 | }
75 |
76 | //判断该用户的权限是否包含operation
77 | return userPermissionSet.contains(PermissionType.OWNER)
78 | || userPermissionSet.contains(PermissionType.ALL)
79 | || userPermissionSet.contains(operation);
80 | }
81 |
82 |
83 | /**
84 | * 保存权限信息,static常驻内存,按table划分到map里
85 | *
86 | * @param permissions
87 | * permissions
88 | */
89 | public void savePermissionList(List permissions) {
90 | PERMISSION_MAP.clear();
91 | for (Permission permission : permissions) {
92 | String key = permission.getTableName();
93 | if (!PERMISSION_MAP.containsKey(key)) {
94 | PERMISSION_MAP.put(key, new ArrayList<>());
95 | }
96 | PERMISSION_MAP.get(key).add(permission);
97 | }
98 | logger.info("所有的权限信息:" + PERMISSION_MAP);
99 | }
100 |
101 | }
102 |
--------------------------------------------------------------------------------
/block/src/main/java/com/magiccube/blockchain/core/manager/SyncManager.java:
--------------------------------------------------------------------------------
1 | package com.magiccube.blockchain.core.manager;
2 |
3 | import com.magiccube.blockchain.core.model.SyncEntity;
4 | import com.magiccube.blockchain.core.repository.SyncRepository;
5 | import org.springframework.data.domain.Pageable;
6 | import org.springframework.stereotype.Service;
7 |
8 | import javax.annotation.Resource;
9 |
10 |
11 | @Service
12 | public class SyncManager {
13 | @Resource
14 | private SyncRepository syncRepository;
15 |
16 | public SyncEntity findLastOne() {
17 | return syncRepository.findTopByOrderByIdDesc();
18 | }
19 |
20 | public SyncEntity save(SyncEntity syncEntity) {
21 | return syncRepository.save(syncEntity);
22 | }
23 |
24 | public Object findAll(Pageable pageable) {
25 | return syncRepository.findAll(pageable);
26 | }
27 |
28 | public void deleteAll() {
29 | syncRepository.deleteAll();
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/block/src/main/java/com/magiccube/blockchain/core/model/MessageEntity.java:
--------------------------------------------------------------------------------
1 | package com.magiccube.blockchain.core.model;
2 |
3 | import com.magiccube.blockchain.core.model.base.BaseEntity;
4 |
5 | import javax.persistence.Entity;
6 | import javax.persistence.Table;
7 |
8 | @Entity
9 | @Table(name = "message")
10 | public class MessageEntity extends BaseEntity {
11 | /**
12 | * 内容
13 | */
14 | private String content;
15 | /**
16 | * 目标用户
17 | */
18 | private String target;
19 | /**
20 | * 来源
21 | */
22 | private String origin;
23 | /**
24 | * 业务id
25 | */
26 | private String messageId;
27 |
28 | @Override
29 | public String toString() {
30 | return "MessageEntity{" +
31 | "content='" + content + '\'' +
32 | ", target='" + target + '\'' +
33 | ", origin='" + origin + '\'' +
34 | ", messageId='" + messageId + '\'' +
35 | '}';
36 | }
37 |
38 | public String getContent() {
39 | return content;
40 | }
41 |
42 | public void setContent(String content) {
43 | this.content = content;
44 | }
45 |
46 | public String getMessageId() {
47 | return messageId;
48 | }
49 |
50 | public void setMessageId(String messageId) {
51 | this.messageId = messageId;
52 | }
53 |
54 | public String getTarget() {
55 | return target;
56 | }
57 |
58 | public void setTarget(String target) {
59 | this.target = target;
60 | }
61 |
62 | public String getOrigin() {
63 | return origin;
64 | }
65 |
66 | public void setOrigin(String origin) {
67 | this.origin = origin;
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/block/src/main/java/com/magiccube/blockchain/core/model/SyncEntity.java:
--------------------------------------------------------------------------------
1 | package com.magiccube.blockchain.core.model;
2 |
3 | import com.magiccube.blockchain.common.CommonUtil;
4 |
5 | import javax.persistence.*;
6 |
7 | @Entity
8 | @Table(name = "sync")
9 | public class SyncEntity {
10 | @Id
11 | @GeneratedValue(strategy = GenerationType.AUTO)
12 | private Long id;
13 | /**
14 | * 已同步的区块hash
15 | */
16 | private String hash;
17 | /**
18 | * 创建时间
19 | */
20 | private Long createTime = CommonUtil.getNow();
21 |
22 | @Override
23 | public String toString() {
24 | return "AsyncEntity{" +
25 | "id=" + id +
26 | ", hash='" + hash + '\'' +
27 | ", createTime=" + createTime +
28 | '}';
29 | }
30 |
31 | public Long getId() {
32 | return id;
33 | }
34 |
35 | public void setId(Long id) {
36 | this.id = id;
37 | }
38 |
39 | public String getHash() {
40 | return hash;
41 | }
42 |
43 | public void setHash(String hash) {
44 | this.hash = hash;
45 | }
46 |
47 | public Long getCreateTime() {
48 | return createTime;
49 | }
50 |
51 | public void setCreateTime(Long createTime) {
52 | this.createTime = createTime;
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/block/src/main/java/com/magiccube/blockchain/core/model/base/BaseEntity.java:
--------------------------------------------------------------------------------
1 | package com.magiccube.blockchain.core.model.base;
2 |
3 | import com.magiccube.blockchain.common.CommonUtil;
4 |
5 | import javax.persistence.GeneratedValue;
6 | import javax.persistence.GenerationType;
7 | import javax.persistence.Id;
8 | import javax.persistence.MappedSuperclass;
9 |
10 | @MappedSuperclass
11 | public class BaseEntity {
12 | @Id
13 | @GeneratedValue(strategy = GenerationType.AUTO)
14 | private Long id;
15 |
16 | private Long createTime;
17 |
18 | private Long updateTime = CommonUtil.getNow();
19 | /**
20 | * 最后操作人
21 | */
22 | private String publicKey;
23 |
24 | public String getPublicKey() {
25 | return publicKey;
26 | }
27 |
28 | public void setPublicKey(String publicKey) {
29 | this.publicKey = publicKey;
30 | }
31 |
32 | public Long getCreateTime() {
33 | return createTime;
34 | }
35 |
36 | public void setCreateTime(Long createTime) {
37 | this.createTime = createTime;
38 | }
39 |
40 | public Long getUpdateTime() {
41 | return updateTime;
42 | }
43 |
44 | public void setUpdateTime(Long updateTime) {
45 | this.updateTime = updateTime;
46 | }
47 |
48 | public Long getId() {
49 | return id;
50 | }
51 |
52 | public void setId(Long id) {
53 | this.id = id;
54 | }
55 |
56 | @Override
57 | public String toString() {
58 | return "BaseEntity{" +
59 | "id=" + id +
60 | ", createTime=" + createTime +
61 | ", updateTime=" + updateTime +
62 | ", publicKey='" + publicKey + '\'' +
63 | '}';
64 | }
65 | }
--------------------------------------------------------------------------------
/block/src/main/java/com/magiccube/blockchain/core/model/convert/ConvertTableName.java:
--------------------------------------------------------------------------------
1 | package com.magiccube.blockchain.core.model.convert;
2 |
3 | import com.magiccube.blockchain.core.model.base.BaseEntity;
4 | import org.springframework.beans.factory.annotation.Qualifier;
5 | import org.springframework.stereotype.Component;
6 |
7 | import javax.annotation.Resource;
8 | import java.util.Map;
9 |
10 | /**
11 | * 表名和实体类的对应
12 | */
13 | @Component
14 | public class ConvertTableName {
15 | @Qualifier(value = "metaMap")
16 | @Resource
17 | private Map> metaMap;
18 |
19 | /**
20 | * 根据表名获取class名
21 | * @return
22 | * 表对应的实体类
23 | */
24 | public Class convertOf(String tableName) {
25 | return metaMap.get(tableName);
26 | }
27 |
28 | /**
29 | * 根据类名取表名
30 | * @param clazz
31 | * 类名
32 | * @return
33 | * 表名
34 | */
35 | public String convertOf(Class clazz) {
36 | for (String key : metaMap.keySet()) {
37 | if (metaMap.get(key).equals(clazz)) {
38 | return key;
39 | }
40 | }
41 | return null;
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/block/src/main/java/com/magiccube/blockchain/core/repository/BaseRepository.java:
--------------------------------------------------------------------------------
1 | package com.magiccube.blockchain.core.repository;
2 |
3 | import com.magiccube.blockchain.core.model.base.BaseEntity;
4 | import org.springframework.data.jpa.repository.JpaRepository;
5 | import org.springframework.data.repository.NoRepositoryBean;
6 |
7 | @NoRepositoryBean
8 | public interface BaseRepository extends JpaRepository {
9 |
10 | }
11 |
--------------------------------------------------------------------------------
/block/src/main/java/com/magiccube/blockchain/core/repository/MessageRepository.java:
--------------------------------------------------------------------------------
1 | package com.magiccube.blockchain.core.repository;
2 |
3 | import com.magiccube.blockchain.core.model.MessageEntity;
4 |
5 | public interface MessageRepository extends BaseRepository {
6 | /**
7 | * 删除一条记录
8 | * @param messageId messageId
9 | */
10 | void deleteByMessageId(String messageId);
11 |
12 | /**
13 | * 查询一个
14 | * @param messageId messageId
15 | * @return MessageEntity
16 | */
17 | MessageEntity findByMessageId(String messageId);
18 | }
19 |
--------------------------------------------------------------------------------
/block/src/main/java/com/magiccube/blockchain/core/repository/SyncRepository.java:
--------------------------------------------------------------------------------
1 | package com.magiccube.blockchain.core.repository;
2 |
3 | import com.magiccube.blockchain.core.model.SyncEntity;
4 | import org.springframework.data.jpa.repository.JpaRepository;
5 |
6 | public interface SyncRepository extends JpaRepository {
7 | SyncEntity findTopByOrderByIdDesc();
8 | }
9 |
--------------------------------------------------------------------------------
/block/src/main/java/com/magiccube/blockchain/core/requestbody/BlockRequestBody.java:
--------------------------------------------------------------------------------
1 | package com.magiccube.blockchain.core.requestbody;
2 |
3 | import com.magiccube.blockchain.block.BlockBody;
4 |
5 | /**
6 | * 生成Block时传参
7 | */
8 | public class BlockRequestBody {
9 | private String publicKey;
10 | private BlockBody blockBody;
11 |
12 | @Override
13 | public String toString() {
14 | return "BlockRequestBody{" +
15 | "publicKey='" + publicKey + '\'' +
16 | ", blockBody=" + blockBody +
17 | '}';
18 | }
19 |
20 | public String getPublicKey() {
21 | return publicKey;
22 | }
23 |
24 | public void setPublicKey(String publicKey) {
25 | this.publicKey = publicKey;
26 | }
27 |
28 | public BlockBody getBlockBody() {
29 | return blockBody;
30 | }
31 |
32 | public void setBlockBody(BlockBody blockBody) {
33 | this.blockBody = blockBody;
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/block/src/main/java/com/magiccube/blockchain/core/requestbody/InstructionBody.java:
--------------------------------------------------------------------------------
1 | package com.magiccube.blockchain.core.requestbody;
2 |
3 | public class InstructionBody {
4 | /**
5 | * 指令的操作,增删改
6 | */
7 | private byte operation;
8 | /**
9 | * 操作的表名
10 | */
11 | private String table;
12 | /**
13 | * 具体内容
14 | */
15 | private String json;
16 | /**
17 | * 原始内容
18 | */
19 | private String oldJson;
20 | /**
21 | * 业务id
22 | */
23 | private String instructionId;
24 | /**
25 | * 私钥
26 | */
27 | private String privateKey;
28 | /**
29 | * 公钥
30 | */
31 | private String publicKey;
32 |
33 | @Override
34 | public String toString() {
35 | return "InstructionBody{" +
36 | "operation=" + operation +
37 | ", table='" + table + '\'' +
38 | ", json='" + json + '\'' +
39 | ", oldJson='" + oldJson + '\'' +
40 | ", instructionId='" + instructionId + '\'' +
41 | ", privateKey='" + privateKey + '\'' +
42 | ", publicKey='" + publicKey + '\'' +
43 | '}';
44 | }
45 |
46 | public String getOldJson() {
47 | return oldJson;
48 | }
49 |
50 | public void setOldJson(String oldJson) {
51 | this.oldJson = oldJson;
52 | }
53 |
54 | public String getInstructionId() {
55 | return instructionId;
56 | }
57 |
58 | public void setInstructionId(String instructionId) {
59 | this.instructionId = instructionId;
60 | }
61 |
62 | public String getPublicKey() {
63 | return publicKey;
64 | }
65 |
66 | public void setPublicKey(String publicKey) {
67 | this.publicKey = publicKey;
68 | }
69 |
70 | public byte getOperation() {
71 | return operation;
72 | }
73 |
74 | public void setOperation(byte operation) {
75 | this.operation = operation;
76 | }
77 |
78 | public String getTable() {
79 | return table;
80 | }
81 |
82 | public void setTable(String table) {
83 | this.table = table;
84 | }
85 |
86 | public String getJson() {
87 | return json;
88 | }
89 |
90 | public void setJson(String json) {
91 | this.json = json;
92 | }
93 |
94 | public String getPrivateKey() {
95 | return privateKey;
96 | }
97 |
98 | public void setPrivateKey(String privateKey) {
99 | this.privateKey = privateKey;
100 | }
101 | }
102 |
--------------------------------------------------------------------------------
/block/src/main/java/com/magiccube/blockchain/core/resthttp/RestTemplateConfig.java:
--------------------------------------------------------------------------------
1 | package com.magiccube.blockchain.core.resthttp;
2 |
3 | import org.springframework.context.annotation.Bean;
4 | import org.springframework.context.annotation.Configuration;
5 | import org.springframework.http.client.ClientHttpRequestFactory;
6 | import org.springframework.http.client.SimpleClientHttpRequestFactory;
7 | import org.springframework.web.client.RestTemplate;
8 |
9 | @Configuration
10 | public class RestTemplateConfig {
11 |
12 | @Bean
13 | public RestTemplate restTemplate(ClientHttpRequestFactory factory) {
14 | return new RestTemplate(factory);
15 | }
16 |
17 | @Bean
18 | public ClientHttpRequestFactory simpleClientHttpRequestFactory() {
19 | SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory();
20 | factory.setReadTimeout(5000);
21 | factory.setConnectTimeout(5000);
22 | return factory;
23 | }
24 | }
--------------------------------------------------------------------------------
/block/src/main/java/com/magiccube/blockchain/core/service/PairKeyService.java:
--------------------------------------------------------------------------------
1 | package com.magiccube.blockchain.core.service;
2 |
3 | import com.magiccube.blockchain.block.PairKey;
4 | import com.magiccube.blockchain.common.TrustSDK;
5 | import com.magiccube.blockchain.common.exception.TrustSDKException;
6 | import org.springframework.stereotype.Service;
7 |
8 | @Service
9 | public class PairKeyService {
10 |
11 | /**
12 | * 生成公私钥对
13 | * @return PairKey
14 | * @throws TrustSDKException TrustSDKException
15 | */
16 | public PairKey generate() throws TrustSDKException {
17 | return TrustSDK.generatePairKey(true);
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/block/src/main/java/com/magiccube/blockchain/core/sqlite/config/DataSourceConfiguration.java:
--------------------------------------------------------------------------------
1 | package com.magiccube.blockchain.core.sqlite.config;
2 |
3 | import org.springframework.beans.factory.annotation.Value;
4 | import org.springframework.boot.autoconfigure.jdbc.DataSourceBuilder;
5 | import org.springframework.context.annotation.Bean;
6 | import org.springframework.context.annotation.Configuration;
7 | import org.sqlite.SQLiteDataSource;
8 |
9 | import javax.sql.DataSource;
10 |
11 |
12 | /**
13 | * 配置sqlite数据库的DataSource
14 | */
15 | @Configuration
16 | public class DataSourceConfiguration {
17 | @Value("${sqlite.dbName}")
18 | private String dbName;
19 |
20 | @Bean(destroyMethod = "", name = "EmbeddeddataSource")
21 | public DataSource dataSource() {
22 | DataSourceBuilder dataSourceBuilder = DataSourceBuilder.create();
23 | dataSourceBuilder.driverClassName("org.sqlite.JDBC");
24 | dataSourceBuilder.url("jdbc:sqlite:" + dbName);
25 | dataSourceBuilder.type(SQLiteDataSource.class);
26 | return dataSourceBuilder.build();
27 | }
28 |
29 | }
30 |
--------------------------------------------------------------------------------
/block/src/main/java/com/magiccube/blockchain/core/sqlite/config/JpaConfiguration.java:
--------------------------------------------------------------------------------
1 | package com.magiccube.blockchain.core.sqlite.config;
2 |
3 | import org.springframework.beans.factory.annotation.Autowired;
4 | import org.springframework.beans.factory.annotation.Qualifier;
5 | import org.springframework.boot.autoconfigure.orm.jpa.JpaProperties;
6 | import org.springframework.boot.orm.jpa.EntityManagerFactoryBuilder;
7 | import org.springframework.context.annotation.Bean;
8 | import org.springframework.context.annotation.Configuration;
9 | import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
10 | import org.springframework.orm.jpa.JpaTransactionManager;
11 | import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
12 | import org.springframework.transaction.annotation.EnableTransactionManagement;
13 |
14 | import javax.annotation.Resource;
15 | import javax.persistence.EntityManagerFactory;
16 | import javax.sql.DataSource;
17 | import java.util.Map;
18 |
19 | @Configuration
20 | @EnableJpaRepositories(
21 | basePackages = "com.magiccube.blockchain.core.repository",
22 | transactionManagerRef = "jpaTransactionManager",
23 | entityManagerFactoryRef = "localContainerEntityManagerFactoryBean"
24 | )
25 | @EnableTransactionManagement
26 | public class JpaConfiguration {
27 | @Resource
28 | private JpaProperties jpaProperties;
29 |
30 | @Autowired
31 | @Bean
32 | public JpaTransactionManager jpaTransactionManager(@Qualifier(value = "EmbeddeddataSource") DataSource
33 | dataSource, EntityManagerFactory
34 | entityManagerFactory) {
35 | JpaTransactionManager jpaTransactionManager
36 | = new JpaTransactionManager();
37 | jpaTransactionManager.setEntityManagerFactory(entityManagerFactory);
38 | jpaTransactionManager.setDataSource(dataSource);
39 |
40 | return jpaTransactionManager;
41 | }
42 |
43 | @Autowired
44 | @Bean
45 | LocalContainerEntityManagerFactoryBean localContainerEntityManagerFactoryBean(@Qualifier(value =
46 | "EmbeddeddataSource") DataSource dataSource, EntityManagerFactoryBuilder builder) {
47 | return builder.dataSource(dataSource)
48 | .packages("com.magiccube.blockchain.core.model")
49 | .properties(getVendorProperties(dataSource))
50 | .build();
51 | }
52 |
53 | private Map getVendorProperties(DataSource dataSource) {
54 | return jpaProperties.getHibernateProperties(dataSource);
55 | }
56 |
57 | }
--------------------------------------------------------------------------------
/block/src/main/java/com/magiccube/blockchain/core/sqlite/config/ModelMetaData.java:
--------------------------------------------------------------------------------
1 | package com.magiccube.blockchain.core.sqlite.config;
2 |
3 | import org.hibernate.SessionFactory;
4 | import org.hibernate.metadata.ClassMetadata;
5 | import org.hibernate.persister.entity.AbstractEntityPersister;
6 | import org.springframework.boot.autoconfigure.AutoConfigureAfter;
7 | import org.springframework.context.annotation.Bean;
8 | import org.springframework.context.annotation.Configuration;
9 |
10 | import javax.persistence.EntityManagerFactory;
11 | import java.util.HashMap;
12 | import java.util.Map;
13 |
14 | /**
15 | * 构建一个存放表名和model实体class的对应关系,如account_entity:AccountEntity.class
16 | *
17 | */
18 | @Configuration
19 | @AutoConfigureAfter(JpaConfiguration.class)
20 | public class ModelMetaData {
21 |
22 | @Bean(name = "metaMap")
23 | public Map metaMap(EntityManagerFactory factory) throws ClassNotFoundException {
24 | if (factory.unwrap(SessionFactory.class) == null) {
25 | throw new NullPointerException("factory is not a hibernate factory");
26 | }
27 | SessionFactory sessionFactory = factory.unwrap(SessionFactory.class);
28 | Map metaMap = sessionFactory.getAllClassMetadata();
29 | Map map = new HashMap<>(metaMap.size());
30 | for (String key : metaMap.keySet()) {
31 | AbstractEntityPersister classMetadata = (AbstractEntityPersister) metaMap
32 | .get(key);
33 | String tableName = classMetadata.getTableName().toLowerCase();
34 | int index = tableName.indexOf(".");
35 | if (index >= 0) {
36 | tableName = tableName.substring(index + 1);
37 | }
38 | map.put(tableName, Class.forName(key));
39 | }
40 | return map;
41 | }
42 |
43 | }
44 |
--------------------------------------------------------------------------------
/block/src/main/java/com/magiccube/blockchain/core/sqlite/config/SQLiteMetadataBuilderInitializer.java:
--------------------------------------------------------------------------------
1 | package com.magiccube.blockchain.core.sqlite.config;
2 |
3 | import org.hibernate.boot.MetadataBuilder;
4 | import org.hibernate.boot.registry.StandardServiceRegistry;
5 | import org.hibernate.boot.spi.MetadataBuilderInitializer;
6 | import org.hibernate.engine.jdbc.dialect.internal.DialectResolverSet;
7 | import org.hibernate.engine.jdbc.dialect.spi.DialectResolver;
8 | import org.jboss.logging.Logger;
9 |
10 | /**
11 | * SQLite工具
12 | */
13 | public class SQLiteMetadataBuilderInitializer implements MetadataBuilderInitializer {
14 |
15 | private final static Logger logger = Logger.getLogger(SQLiteMetadataBuilderInitializer.class);
16 |
17 | @Override
18 | public void contribute(MetadataBuilder metadataBuilder, StandardServiceRegistry serviceRegistry) {
19 | DialectResolver dialectResolver = serviceRegistry.getService(DialectResolver.class);
20 |
21 | if (!(dialectResolver instanceof DialectResolverSet)) {
22 | logger.warnf("DialectResolver '%s' is not an instance of DialectResolverSet, not registering SQLiteDialect",
23 | dialectResolver);
24 | return;
25 | }
26 |
27 | ((DialectResolverSet) dialectResolver).addResolver(resolver);
28 | }
29 |
30 | static private final SQLiteDialect dialect = new SQLiteDialect();
31 |
32 | static private final DialectResolver resolver = (DialectResolver) info -> {
33 | if (info.getDatabaseName().equals("SQLite")) {
34 | return dialect;
35 | }
36 |
37 | return null;
38 | };
39 | }
--------------------------------------------------------------------------------
/block/src/main/java/com/magiccube/blockchain/core/sqlite/config/identity/SQLiteDialectIdentityColumnSupport.java:
--------------------------------------------------------------------------------
1 | package com.magiccube.blockchain.core.sqlite.config.identity;
2 |
3 | import org.hibernate.dialect.Dialect;
4 | import org.hibernate.dialect.identity.IdentityColumnSupportImpl;
5 |
6 | public class SQLiteDialectIdentityColumnSupport extends IdentityColumnSupportImpl {
7 | public SQLiteDialectIdentityColumnSupport(Dialect dialect) {
8 | super(dialect);
9 | }
10 |
11 | @Override
12 | public boolean supportsIdentityColumns() {
13 | return true;
14 | }
15 |
16 | /*
17 | public boolean supportsInsertSelectIdentity() {
18 | return true; // As specified in NHibernate dialect
19 | }
20 | */
21 |
22 | @Override
23 | public boolean hasDataTypeInIdentityColumn() {
24 | // As specified in NHibernate dialect
25 | // FIXME true
26 | return false;
27 | }
28 |
29 | /*
30 | public String appendIdentitySelectToInsert(String insertString) {
31 | return new StringBuffer(insertString.length()+30). // As specified in NHibernate dialect
32 | append(insertString).
33 | append("; ").append(getIdentitySelectString()).
34 | toString();
35 | }
36 | */
37 |
38 | @Override
39 | public String getIdentitySelectString(String table, String column, int type) {
40 | return "select last_insert_rowid()";
41 | }
42 |
43 | @Override
44 | public String getIdentityColumnString(int type) {
45 | // return "integer primary key autoincrement";
46 | // FIXME "autoincrement"
47 | return "integer";
48 | }
49 | }
--------------------------------------------------------------------------------
/block/src/main/java/com/magiccube/blockchain/core/sqlparser/AbstractSqlParser.java:
--------------------------------------------------------------------------------
1 | package com.magiccube.blockchain.core.sqlparser;
2 |
3 | import com.magiccube.blockchain.core.model.base.BaseEntity;
4 |
5 | public abstract class AbstractSqlParser {
6 | /**
7 | * 解析sql的方法
8 | * @param operation 是什么操作
9 | * @param id 主键
10 | * @param entity 对象entity
11 | */
12 | abstract void parse(byte operation, String id, T entity);
13 |
14 | /**
15 | * 对象的类
16 | *
17 | * @return Class
18 | */
19 | abstract Class getEntityClass();
20 | }
21 |
--------------------------------------------------------------------------------
/block/src/main/java/com/magiccube/blockchain/core/sqlparser/InstructionParser.java:
--------------------------------------------------------------------------------
1 | package com.magiccube.blockchain.core.sqlparser;
2 |
3 | import com.magiccube.blockchain.block.InstructionBase;
4 |
5 | public interface InstructionParser {
6 | boolean parse(InstructionBase instructionBase);
7 | }
8 |
--------------------------------------------------------------------------------
/block/src/main/java/com/magiccube/blockchain/core/sqlparser/InstructionParserImpl.java:
--------------------------------------------------------------------------------
1 | package com.magiccube.blockchain.core.sqlparser;
2 |
3 | import javax.annotation.Resource;
4 |
5 | import org.springframework.stereotype.Service;
6 |
7 | import com.magiccube.blockchain.block.Instruction;
8 | import com.magiccube.blockchain.block.InstructionBase;
9 | import com.magiccube.blockchain.common.FastJsonUtil;
10 | import com.magiccube.blockchain.core.model.base.BaseEntity;
11 | import com.magiccube.blockchain.core.model.convert.ConvertTableName;
12 |
13 | /**
14 | * 将区块内指令解析并入库
15 | */
16 | @Service
17 | public class InstructionParserImpl implements InstructionParser {
18 | @Resource
19 | private ConvertTableName convertTableName;
20 | @Resource
21 | private AbstractSqlParser[] sqlParsers;
22 |
23 | @Override
24 | public boolean parse(InstructionBase instructionBase) {
25 | byte operation = instructionBase.getOperation();
26 | String table = instructionBase.getTable();
27 | String json = instructionBase.getOldJson();
28 | //表对应的类名,如MessageEntity.class
29 | Class clazz = convertTableName.convertOf(table);
30 | T object = FastJsonUtil.toBean(json, clazz);
31 | for (AbstractSqlParser sqlParser : sqlParsers) {
32 | if (clazz.equals(sqlParser.getEntityClass())) {
33 | if(instructionBase instanceof Instruction){
34 | object.setPublicKey(((Instruction)instructionBase).getPublicKey());
35 | }
36 | sqlParser.parse(operation, instructionBase.getInstructionId(), object);
37 | break;
38 | }
39 | }
40 |
41 | return true;
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/block/src/main/java/com/magiccube/blockchain/core/sqlparser/MessageSqlParser.java:
--------------------------------------------------------------------------------
1 | package com.magiccube.blockchain.core.sqlparser;
2 |
3 | import javax.annotation.Resource;
4 |
5 | import org.springframework.stereotype.Service;
6 |
7 | import com.magiccube.blockchain.block.Operation;
8 | import com.magiccube.blockchain.common.CommonUtil;
9 | import com.magiccube.blockchain.core.model.MessageEntity;
10 | import com.magiccube.blockchain.core.repository.MessageRepository;
11 |
12 | import cn.hutool.core.bean.BeanUtil;
13 | import cn.hutool.core.bean.copier.CopyOptions;
14 |
15 | /**
16 | * 解析语句入库的具体实现,Message表的
17 | */
18 | @Service
19 | public class MessageSqlParser extends AbstractSqlParser {
20 | @Resource
21 | private MessageRepository messageRepository;
22 |
23 | @Override
24 | public void parse(byte operation, String messageId, MessageEntity entity) {
25 | if (Operation.ADD == operation) {
26 | entity.setCreateTime(CommonUtil.getNow());
27 | entity.setMessageId(messageId);
28 | messageRepository.save(entity);
29 | } else if (Operation.DELETE == operation) {
30 | messageRepository.deleteByMessageId(messageId);
31 | } else if (Operation.UPDATE == operation) {
32 | MessageEntity messageEntity = messageRepository.findByMessageId(messageId);
33 | BeanUtil.copyProperties(entity, messageEntity, CopyOptions.create().setIgnoreNullValue(true).setIgnoreProperties("id", "createTime"));
34 | messageRepository.save(messageEntity);
35 | }
36 | }
37 |
38 | @Override
39 | public Class getEntityClass() {
40 | return MessageEntity.class;
41 | }
42 |
43 | }
44 |
--------------------------------------------------------------------------------
/block/src/main/java/com/magiccube/blockchain/socket/base/AbstractAioHandler.java:
--------------------------------------------------------------------------------
1 | package com.magiccube.blockchain.socket.base;
2 |
3 | import com.magiccube.blockchain.socket.packet.BlockPacket;
4 | import org.tio.core.ChannelContext;
5 | import org.tio.core.GroupContext;
6 | import org.tio.core.exception.AioDecodeException;
7 | import org.tio.core.intf.AioHandler;
8 | import org.tio.core.intf.Packet;
9 |
10 | import java.nio.ByteBuffer;
11 |
12 | /**
13 | * @author tanyaowu
14 | * 2017年3月27日 上午12:14:12
15 | */
16 | public abstract class AbstractAioHandler implements AioHandler {
17 | /**
18 | * 解码:把接收到的ByteBuffer,解码成应用可以识别的业务消息包
19 | * 消息头:type + bodyLength
20 | * 消息体:byte[]
21 | */
22 | @Override
23 | public BlockPacket decode(ByteBuffer buffer, ChannelContext channelContext) throws AioDecodeException {
24 | int readableLength = buffer.limit() - buffer.position();
25 | if (readableLength < BlockPacket.HEADER_LENGTH) {
26 | return null;
27 | }
28 |
29 | //消息类型
30 | byte type = buffer.get();
31 |
32 | int bodyLength = buffer.getInt();
33 |
34 | if (bodyLength < 0) {
35 | throw new AioDecodeException("bodyLength [" + bodyLength + "] is not right, remote:" + channelContext
36 | .getClientNode());
37 | }
38 |
39 | int neededLength = BlockPacket.HEADER_LENGTH + bodyLength;
40 | int test = readableLength - neededLength;
41 | // 不够消息体长度(剩下的buffer组不了消息体)
42 | if (test < 0) {
43 | return null;
44 | }
45 | BlockPacket imPacket = new BlockPacket();
46 | imPacket.setType(type);
47 | if (bodyLength > 0) {
48 | byte[] dst = new byte[bodyLength];
49 | buffer.get(dst);
50 | imPacket.setBody(dst);
51 | }
52 | return imPacket;
53 | }
54 |
55 | /**
56 | * 编码:把业务消息包编码为可以发送的ByteBuffer
57 | * 消息头:type + bodyLength
58 | * 消息体:byte[]
59 | */
60 | @Override
61 | public ByteBuffer encode(Packet packet, GroupContext groupContext, ChannelContext channelContext) {
62 | BlockPacket showcasePacket = (BlockPacket) packet;
63 | byte[] body = showcasePacket.getBody();
64 | int bodyLen = 0;
65 | if (body != null) {
66 | bodyLen = body.length;
67 | }
68 |
69 | //总长度是消息头的长度+消息体的长度
70 | int allLen = BlockPacket.HEADER_LENGTH + bodyLen;
71 |
72 | ByteBuffer buffer = ByteBuffer.allocate(allLen);
73 | buffer.order(groupContext.getByteOrder());
74 |
75 | //写入消息类型
76 | buffer.put(showcasePacket.getType());
77 | //写入消息体长度
78 | buffer.putInt(bodyLen);
79 |
80 | //写入消息体
81 | if (body != null) {
82 | buffer.put(body);
83 | }
84 | return buffer;
85 | }
86 | }
87 |
--------------------------------------------------------------------------------
/block/src/main/java/com/magiccube/blockchain/socket/base/AbstractBlockHandler.java:
--------------------------------------------------------------------------------
1 | package com.magiccube.blockchain.socket.base;
2 |
3 | import com.magiccube.blockchain.socket.body.BaseBody;
4 | import com.magiccube.blockchain.socket.common.Const;
5 | import com.magiccube.blockchain.socket.packet.BlockPacket;
6 | import org.tio.core.ChannelContext;
7 | import org.tio.utils.json.Json;
8 |
9 | /**
10 | * 基础handler
11 | * @author tanyaowu
12 | * 2017年3月27日 下午9:56:16
13 | */
14 | public abstract class AbstractBlockHandler implements HandlerInterface {
15 |
16 | public AbstractBlockHandler() {
17 | }
18 |
19 | public abstract Class bodyClass();
20 |
21 | @Override
22 | public Object handler(BlockPacket packet, ChannelContext channelContext) throws Exception {
23 | String jsonStr;
24 | T bsBody = null;
25 | if (packet.getBody() != null) {
26 | jsonStr = new String(packet.getBody(), Const.CHARSET);
27 | bsBody = Json.toBean(jsonStr, bodyClass());
28 | }
29 |
30 | return handler(packet, bsBody, channelContext);
31 | }
32 |
33 | /**
34 | * 实际的handler处理
35 | * @param packet packet
36 | * @param bsBody 解析后的对象
37 | * @param channelContext channelContext
38 | * @return 用不上
39 | * @throws Exception Exception
40 | */
41 | public abstract Object handler(BlockPacket packet, T bsBody, ChannelContext channelContext) throws Exception;
42 |
43 | }
44 |
--------------------------------------------------------------------------------
/block/src/main/java/com/magiccube/blockchain/socket/base/HandlerInterface.java:
--------------------------------------------------------------------------------
1 | package com.magiccube.blockchain.socket.base;
2 |
3 | import com.magiccube.blockchain.socket.packet.BlockPacket;
4 | import org.tio.core.ChannelContext;
5 |
6 | /**
7 | * 业务处理器接口
8 | */
9 | public interface HandlerInterface {
10 |
11 | /**
12 | * handler方法在此封装转换
13 | * @param packet packet
14 | * @param channelContext channelContext
15 | * @return Object对象
16 | * @throws Exception Exception
17 | */
18 | Object handler(BlockPacket packet, ChannelContext channelContext) throws Exception;
19 |
20 | }
21 |
--------------------------------------------------------------------------------
/block/src/main/java/com/magiccube/blockchain/socket/body/BaseBody.java:
--------------------------------------------------------------------------------
1 | package com.magiccube.blockchain.socket.body;
2 |
3 | import com.magiccube.blockchain.common.AppId;
4 | import com.magiccube.blockchain.common.CommonUtil;
5 |
6 | /**
7 | *
8 | * @author tanyaowu
9 | * 2017年3月27日 上午12:12:17
10 | */
11 | public class BaseBody {
12 |
13 | /**
14 | * 消息发送时间
15 | */
16 | private Long time = System.currentTimeMillis();
17 | /**
18 | * 每条消息的唯一id
19 | */
20 | private String messageId = CommonUtil.generateUuid();
21 | /**
22 | * 回复的哪条消息
23 | */
24 | private String responseMsgId;
25 | /**
26 | * 自己是谁
27 | */
28 | private String appId = AppId.value;
29 |
30 | public BaseBody() {
31 | }
32 |
33 | /**
34 | * @return the time
35 | */
36 | public Long getTime() {
37 | return time;
38 | }
39 |
40 | /**
41 | * @param time the time to set
42 | */
43 | public void setTime(Long time) {
44 | this.time = time;
45 | }
46 |
47 | public String getMessageId() {
48 | return messageId;
49 | }
50 |
51 | public void setMessageId(String messageId) {
52 | this.messageId = messageId;
53 | }
54 |
55 | public String getResponseMsgId() {
56 | return responseMsgId;
57 | }
58 |
59 | public void setResponseMsgId(String responseMsgId) {
60 | this.responseMsgId = responseMsgId;
61 | }
62 |
63 | public String getAppId() {
64 | return appId;
65 | }
66 |
67 | public void setAppId(String appId) {
68 | this.appId = appId;
69 | }
70 |
71 | @Override
72 | public String toString() {
73 | return "BaseBody{" +
74 | "time=" + time +
75 | ", messageId='" + messageId + '\'' +
76 | ", responseMsgId='" + responseMsgId + '\'' +
77 | '}';
78 | }
79 | }
80 |
--------------------------------------------------------------------------------
/block/src/main/java/com/magiccube/blockchain/socket/body/BlockHash.java:
--------------------------------------------------------------------------------
1 | package com.magiccube.blockchain.socket.body;
2 |
3 | public class BlockHash {
4 | private String hash;
5 | private String prevHash;
6 | private String appId;
7 |
8 | public BlockHash() {
9 | }
10 |
11 | public BlockHash(String hash, String prevHash, String appId) {
12 | this.hash = hash;
13 | this.prevHash = prevHash;
14 | this.appId = appId;
15 | }
16 |
17 | public String getPrevHash() {
18 | return prevHash;
19 | }
20 |
21 | public void setPrevHash(String prevHash) {
22 | this.prevHash = prevHash;
23 | }
24 |
25 | public String getHash() {
26 | return hash;
27 | }
28 |
29 | public void setHash(String hash) {
30 | this.hash = hash;
31 | }
32 |
33 | public String getAppId() {
34 | return appId;
35 | }
36 |
37 | public void setAppId(String appId) {
38 | this.appId = appId;
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/block/src/main/java/com/magiccube/blockchain/socket/body/HeartBeatBody.java:
--------------------------------------------------------------------------------
1 | package com.magiccube.blockchain.socket.body;
2 |
3 | @Deprecated
4 | public class HeartBeatBody extends BaseBody {
5 | /**
6 | * text
7 | */
8 | private String text;
9 |
10 | public HeartBeatBody() {
11 | super();
12 | }
13 |
14 | public HeartBeatBody(String text) {
15 | super();
16 | this.text = text;
17 | }
18 |
19 | public String getText() {
20 | return text;
21 | }
22 |
23 | public void setText(String text) {
24 | this.text = text;
25 | }
26 |
27 | @Override
28 | public String toString() {
29 | return "HeartBeatBody{" +
30 | "text='" + text + '\'' +
31 | '}';
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/block/src/main/java/com/magiccube/blockchain/socket/body/RpcBlockBody.java:
--------------------------------------------------------------------------------
1 | package com.magiccube.blockchain.socket.body;
2 |
3 | import com.magiccube.blockchain.block.Block;
4 |
5 | /**
6 | * body里是一个block信息
7 | */
8 | public class RpcBlockBody extends BaseBody {
9 | /**
10 | * blockJson
11 | */
12 | private Block block;
13 |
14 | public RpcBlockBody() {
15 | super();
16 | }
17 |
18 | public RpcBlockBody(Block block) {
19 | super();
20 | this.block = block;
21 | }
22 |
23 | public Block getBlock() {
24 | return block;
25 | }
26 |
27 | public void setBlock(Block block) {
28 | this.block = block;
29 | }
30 |
31 | @Override
32 | public String toString() {
33 | return "BlockBody{" +
34 | "block=" + block +
35 | '}';
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/block/src/main/java/com/magiccube/blockchain/socket/body/RpcCheckBlockBody.java:
--------------------------------------------------------------------------------
1 | package com.magiccube.blockchain.socket.body;
2 |
3 | import com.magiccube.blockchain.block.Block;
4 |
5 | /**
6 | * 校验block是否合法,同意、拒绝区块生成请求
7 | */
8 | public class RpcCheckBlockBody extends RpcBlockBody {
9 | /**
10 | * 0是正常同意,-1区块number错误,-2没有权限,-3hash错误,-4时间错误,-10不合法的next block
11 | */
12 | private int code;
13 | /**
14 | * 附带的message
15 | */
16 | private String message;
17 |
18 | public RpcCheckBlockBody() {
19 | }
20 |
21 | public RpcCheckBlockBody(int code, String message) {
22 | this(code, message, null);
23 | }
24 |
25 | public RpcCheckBlockBody(int code, String message, Block block) {
26 | super(block);
27 | this.code = code;
28 | this.message = message;
29 | }
30 |
31 | public int getCode() {
32 | return code;
33 | }
34 |
35 | public void setCode(int code) {
36 | this.code = code;
37 | }
38 |
39 | public String getMessage() {
40 | return message;
41 | }
42 |
43 | public void setMessage(String message) {
44 | this.message = message;
45 | }
46 |
47 | @Override
48 | public String toString() {
49 | return "RpcCheckBlockBody{" +
50 | "code=" + code +
51 | ", message='" + message + '\'' +
52 | '}';
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/block/src/main/java/com/magiccube/blockchain/socket/body/RpcNextBlockBody.java:
--------------------------------------------------------------------------------
1 | package com.magiccube.blockchain.socket.body;
2 |
3 | /**
4 | * 请求next block时用的包装类
5 | */
6 | public class RpcNextBlockBody extends BaseBody {
7 | /**
8 | * blockHash
9 | */
10 | private String hash;
11 | /**
12 | * 上一个hash
13 | */
14 | private String prevHash;
15 |
16 | public RpcNextBlockBody() {
17 | super();
18 | }
19 |
20 | public RpcNextBlockBody(String hash, String prevHash) {
21 | super();
22 | this.hash = hash;
23 | this.prevHash = prevHash;
24 | }
25 |
26 | public String getPrevHash() {
27 | return prevHash;
28 | }
29 |
30 | public void setPrevHash(String prevHash) {
31 | this.prevHash = prevHash;
32 | }
33 |
34 | public String getHash() {
35 | return hash;
36 | }
37 |
38 | public void setHash(String hash) {
39 | this.hash = hash;
40 | }
41 |
42 | @Override
43 | public String toString() {
44 | return "RpcNextBlockBody{" +
45 | "hash='" + hash + '\'' +
46 | ", prevHash='" + prevHash + '\'' +
47 | '}';
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/block/src/main/java/com/magiccube/blockchain/socket/body/RpcSimpleBlockBody.java:
--------------------------------------------------------------------------------
1 | package com.magiccube.blockchain.socket.body;
2 |
3 |
4 | public class RpcSimpleBlockBody extends BaseBody {
5 | /**
6 | * blockHash
7 | */
8 | private String hash;
9 |
10 | public RpcSimpleBlockBody() {
11 | super();
12 | }
13 |
14 | public RpcSimpleBlockBody(String hash) {
15 | super();
16 | this.hash = hash;
17 | }
18 |
19 | public String getHash() {
20 | return hash;
21 | }
22 |
23 | public void setHash(String hash) {
24 | this.hash = hash;
25 | }
26 |
27 | @Override
28 | public String toString() {
29 | return "RpcSimpleBlockBody{" +
30 | "hash='" + hash + '\'' +
31 | '}';
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/block/src/main/java/com/magiccube/blockchain/socket/body/VoteBody.java:
--------------------------------------------------------------------------------
1 | package com.magiccube.blockchain.socket.body;
2 |
3 | import com.magiccube.blockchain.socket.pbft.msg.VoteMsg;
4 |
5 | /**
6 | * pbft投票
7 | */
8 | public class VoteBody extends BaseBody {
9 | private VoteMsg voteMsg;
10 |
11 | public VoteBody() {
12 | super();
13 | }
14 |
15 | public VoteBody(VoteMsg voteMsg) {
16 | super();
17 | this.voteMsg = voteMsg;
18 | }
19 |
20 | public VoteMsg getVoteMsg() {
21 | return voteMsg;
22 | }
23 |
24 | public void setVoteMsg(VoteMsg voteMsg) {
25 | this.voteMsg = voteMsg;
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/block/src/main/java/com/magiccube/blockchain/socket/client/BlockClientAioHandler.java:
--------------------------------------------------------------------------------
1 | package com.magiccube.blockchain.socket.client;
2 |
3 | import com.magiccube.blockchain.ApplicationContextProvider;
4 | import com.magiccube.blockchain.socket.base.AbstractAioHandler;
5 | import com.magiccube.blockchain.socket.distruptor.base.BaseEvent;
6 | import com.magiccube.blockchain.socket.distruptor.base.MessageProducer;
7 | import com.magiccube.blockchain.socket.packet.BlockPacket;
8 | import org.tio.client.intf.ClientAioHandler;
9 | import org.tio.core.ChannelContext;
10 | import org.tio.core.intf.Packet;
11 |
12 | public class BlockClientAioHandler extends AbstractAioHandler implements ClientAioHandler {
13 |
14 | @Override
15 | public BlockPacket heartbeatPacket() {
16 | //心跳包的内容就是隔一段时间向别的节点获取一次下一步区块(带着自己的最新Block获取别人的next Block)
17 | //return NextBlockPacketBuilder.build();
18 | return null;
19 | }
20 |
21 | /**
22 | * server端返回的响应会先进到该方法,将消息全丢到Disruptor中
23 | */
24 | @Override
25 | public void handler(Packet packet, ChannelContext channelContext) {
26 | BlockPacket blockPacket = (BlockPacket) packet;
27 |
28 | //使用Disruptor来publish消息。所有收到的消息都进入Disruptor,同BlockServerAioHandler
29 | ApplicationContextProvider.getBean(MessageProducer.class).publish(new BaseEvent(blockPacket, channelContext));
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/block/src/main/java/com/magiccube/blockchain/socket/client/BlockClientAioListener.java:
--------------------------------------------------------------------------------
1 | package com.magiccube.blockchain.socket.client;
2 |
3 | import org.slf4j.Logger;
4 | import org.slf4j.LoggerFactory;
5 | import org.tio.client.intf.ClientAioListener;
6 | import org.tio.core.Aio;
7 | import org.tio.core.ChannelContext;
8 | import org.tio.core.intf.Packet;
9 |
10 | import com.magiccube.blockchain.ApplicationContextProvider;
11 | import com.magiccube.blockchain.core.event.NodesConnectedEvent;
12 |
13 | /**
14 | * client端对各个server连接的情况回调。
15 | * 当某个server的心跳超时(2min)时,Aio会从group里remove掉该连接,需要在重新connect后重新加入group
16 | */
17 | public class BlockClientAioListener implements ClientAioListener {
18 | private Logger logger = LoggerFactory.getLogger(getClass());
19 |
20 | @Override
21 | public void onAfterConnected(ChannelContext channelContext, boolean isConnected, boolean isReconnect) throws Exception {
22 | // if (isConnected) {
23 | // logger.info("连接成功:server地址为-" + channelContext.getServerNode());
24 | // Aio.bindGroup(channelContext, Const.GROUP_NAME);
25 | // } else {
26 | // logger.info("连接失败:server地址为-" + channelContext.getServerNode());
27 | // }
28 | ApplicationContextProvider.publishEvent(new NodesConnectedEvent(channelContext));
29 | }
30 |
31 | @Override
32 | public void onBeforeClose(ChannelContext channelContext, Throwable throwable, String s, boolean b) {
33 | logger.info("连接关闭:server地址为-" + channelContext.getServerNode());
34 | Aio.unbindGroup(channelContext);
35 | }
36 |
37 | @Override
38 | public void onAfterDecoded(ChannelContext channelContext, Packet packet, int i) throws Exception {
39 |
40 | }
41 |
42 | @Override
43 | public void onAfterReceivedBytes(ChannelContext channelContext, int i) throws Exception {
44 |
45 | }
46 |
47 | @Override
48 | public void onAfterSent(ChannelContext channelContext, Packet packet, boolean b) throws Exception {
49 |
50 | }
51 |
52 | @Override
53 | public void onAfterHandled(ChannelContext channelContext, Packet packet, long l) throws Exception {
54 |
55 | }
56 |
57 | }
58 |
--------------------------------------------------------------------------------
/block/src/main/java/com/magiccube/blockchain/socket/client/BlockGeneratedListener.java:
--------------------------------------------------------------------------------
1 | package com.magiccube.blockchain.socket.client;
2 |
3 | import com.magiccube.blockchain.block.Block;
4 | import com.magiccube.blockchain.core.event.AddBlockEvent;
5 | import com.magiccube.blockchain.socket.body.RpcSimpleBlockBody;
6 | import com.magiccube.blockchain.socket.packet.BlockPacket;
7 | import com.magiccube.blockchain.socket.packet.PacketBuilder;
8 | import com.magiccube.blockchain.socket.packet.PacketType;
9 | import org.springframework.context.event.EventListener;
10 | import org.springframework.core.annotation.Order;
11 | import org.springframework.stereotype.Component;
12 |
13 | import javax.annotation.Resource;
14 |
15 | /**
16 | * 本地新生成区块后,需要通知所有group内的节点
17 | */
18 | @Component
19 | public class BlockGeneratedListener {
20 | @Resource
21 | private PacketSender packetSender;
22 |
23 | @Order(2)
24 | @EventListener(AddBlockEvent.class)
25 | public void blockGenerated(AddBlockEvent addBlockEvent) {
26 | Block block = (Block) addBlockEvent.getSource();
27 | BlockPacket blockPacket = new PacketBuilder<>().setType(PacketType.GENERATE_COMPLETE_REQUEST).setBody(new
28 | RpcSimpleBlockBody(block.getHash())).build();
29 |
30 | //广播给其他人做验证
31 | packetSender.sendGroup(blockPacket);
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/block/src/main/java/com/magiccube/blockchain/socket/client/ClientContextConfig.java:
--------------------------------------------------------------------------------
1 | package com.magiccube.blockchain.socket.client;
2 |
3 | import org.springframework.context.annotation.Bean;
4 | import org.springframework.context.annotation.Configuration;
5 | import org.tio.client.ClientGroupContext;
6 | import org.tio.client.ReconnConf;
7 | import org.tio.client.intf.ClientAioHandler;
8 | import org.tio.client.intf.ClientAioListener;
9 |
10 | /**
11 | * 配置ClientGroupContext
12 | */
13 | @Configuration
14 | public class ClientContextConfig {
15 |
16 | /**
17 | * 构建客户端连接的context
18 | * @return
19 | * ClientGroupContext
20 | */
21 | @Bean
22 | public ClientGroupContext clientGroupContext() {
23 | //handler, 包括编码、解码、消息处理
24 | ClientAioHandler clientAioHandler = new BlockClientAioHandler();
25 | //事件监听器,可以为null,但建议自己实现该接口
26 | ClientAioListener clientAioListener = new BlockClientAioListener();
27 | //断链后自动连接的,不想自动连接请设为null
28 | ReconnConf reconnConf = new ReconnConf(5000L, 20);
29 | ClientGroupContext clientGroupContext = new ClientGroupContext(clientAioHandler, clientAioListener,
30 | reconnConf);
31 |
32 | //clientGroupContext.setHeartbeatTimeout(Const.TIMEOUT);
33 | return clientGroupContext;
34 | }
35 |
36 | }
37 |
--------------------------------------------------------------------------------
/block/src/main/java/com/magiccube/blockchain/socket/client/PacketSender.java:
--------------------------------------------------------------------------------
1 | package com.magiccube.blockchain.socket.client;
2 |
3 | import com.magiccube.blockchain.ApplicationContextProvider;
4 | import com.magiccube.blockchain.core.event.ClientRequestEvent;
5 | import com.magiccube.blockchain.socket.packet.BlockPacket;
6 | import org.springframework.stereotype.Component;
7 | import org.tio.client.ClientGroupContext;
8 | import org.tio.core.Aio;
9 |
10 | import javax.annotation.Resource;
11 |
12 | import static com.magiccube.blockchain.socket.common.Const.GROUP_NAME;
13 |
14 | /**
15 | * 发送消息的工具类
16 | */
17 | @Component
18 | public class PacketSender {
19 | @Resource
20 | private ClientGroupContext clientGroupContext;
21 |
22 | public void sendGroup(BlockPacket blockPacket) {
23 | //对外发出client请求事件
24 | ApplicationContextProvider.publishEvent(new ClientRequestEvent(blockPacket));
25 | //发送到一个group
26 | Aio.sendToGroup(clientGroupContext, GROUP_NAME, blockPacket);
27 | }
28 |
29 | }
30 |
--------------------------------------------------------------------------------
/block/src/main/java/com/magiccube/blockchain/socket/common/Const.java:
--------------------------------------------------------------------------------
1 | package com.magiccube.blockchain.socket.common;
2 |
3 | public interface Const {
4 | /**
5 | * 服务器地址
6 | */
7 | String SERVER = "127.0.0.1";
8 | /**
9 | * 服务器分组名
10 | */
11 | String GROUP_NAME = "block_group";
12 | /**
13 | * 监听端口
14 | */
15 | int PORT = 6789;
16 |
17 | /**
18 | * 心跳超时时间
19 | */
20 | int TIMEOUT = 5000;
21 |
22 | String CHARSET = "utf-8";
23 | }
24 |
--------------------------------------------------------------------------------
/block/src/main/java/com/magiccube/blockchain/socket/distruptor/DisruptorClientConsumer.java:
--------------------------------------------------------------------------------
1 | package com.magiccube.blockchain.socket.distruptor;
2 |
3 | import cn.hutool.core.util.StrUtil;
4 | import com.magiccube.blockchain.common.AppId;
5 | import com.magiccube.blockchain.socket.distruptor.base.BaseEvent;
6 | import com.magiccube.blockchain.socket.distruptor.base.MessageConsumer;
7 | import com.magiccube.blockchain.socket.base.AbstractBlockHandler;
8 | import com.magiccube.blockchain.socket.body.BaseBody;
9 | import com.magiccube.blockchain.socket.handler.client.FetchBlockResponseHandler;
10 | import com.magiccube.blockchain.socket.handler.client.NextBlockResponseHandler;
11 | import com.magiccube.blockchain.socket.handler.client.TotalBlockInfoResponseHandler;
12 | import com.magiccube.blockchain.socket.packet.BlockPacket;
13 | import com.magiccube.blockchain.socket.packet.PacketType;
14 | import org.slf4j.Logger;
15 | import org.slf4j.LoggerFactory;
16 | import org.springframework.stereotype.Component;
17 | import org.tio.utils.json.Json;
18 |
19 | import java.util.HashMap;
20 | import java.util.Map;
21 |
22 | /**
23 | * 所有server发来的消息都在这里处理
24 | */
25 | @Component
26 | public class DisruptorClientConsumer implements MessageConsumer {
27 | private static Map> handlerMap = new HashMap<>();
28 | private Logger logger = LoggerFactory.getLogger(getClass());
29 |
30 | static {
31 | handlerMap.put(PacketType.TOTAL_BLOCK_INFO_RESPONSE, new TotalBlockInfoResponseHandler());
32 | handlerMap.put(PacketType.NEXT_BLOCK_INFO_RESPONSE, new NextBlockResponseHandler());
33 | handlerMap.put(PacketType.FETCH_BLOCK_INFO_RESPONSE, new FetchBlockResponseHandler());
34 | }
35 |
36 | @Override
37 | public void receive(BaseEvent baseEvent) throws Exception {
38 | BlockPacket blockPacket = baseEvent.getBlockPacket();
39 | Byte type = blockPacket.getType();
40 | AbstractBlockHandler> blockHandler = handlerMap.get(type);
41 | if (blockHandler == null) {
42 | return;
43 | }
44 |
45 | //消费消息
46 | BaseBody baseBody = Json.toBean(new String(blockPacket.getBody()), BaseBody.class);
47 | //logger.info("收到来自于<" + baseBody.getAppId() + ">针对msg<" + baseBody.getResponseMsgId() + ">的回应");
48 |
49 | String appId = baseBody.getAppId();
50 | if (StrUtil.equals(AppId.value, appId)) {
51 | //是本机
52 | //return;
53 | }
54 |
55 | blockHandler.handler(blockPacket, baseEvent.getChannelContext());
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/block/src/main/java/com/magiccube/blockchain/socket/distruptor/DisruptorClientHandler.java:
--------------------------------------------------------------------------------
1 | package com.magiccube.blockchain.socket.distruptor;
2 |
3 | import com.lmax.disruptor.EventHandler;
4 | import com.magiccube.blockchain.ApplicationContextProvider;
5 | import com.magiccube.blockchain.socket.distruptor.base.BaseEvent;
6 |
7 |
8 | public class DisruptorClientHandler implements EventHandler {
9 |
10 | @Override
11 | public void onEvent(BaseEvent baseEvent, long sequence, boolean endOfBatch) throws Exception {
12 | ApplicationContextProvider.getBean(DisruptorClientConsumer.class).receive(baseEvent);
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/block/src/main/java/com/magiccube/blockchain/socket/distruptor/DisruptorConfig.java:
--------------------------------------------------------------------------------
1 | package com.magiccube.blockchain.socket.distruptor;
2 |
3 | import com.lmax.disruptor.BlockingWaitStrategy;
4 | import com.lmax.disruptor.dsl.Disruptor;
5 | import com.lmax.disruptor.dsl.ProducerType;
6 | import com.magiccube.blockchain.socket.distruptor.base.BaseEvent;
7 | import com.magiccube.blockchain.socket.distruptor.base.BaseEventFactory;
8 | import com.magiccube.blockchain.socket.distruptor.base.MessageProducer;
9 | import org.springframework.context.annotation.Bean;
10 | import org.springframework.context.annotation.Configuration;
11 |
12 | import java.util.concurrent.Executors;
13 | import java.util.concurrent.ThreadFactory;
14 |
15 |
16 | @Configuration
17 | public class DisruptorConfig {
18 |
19 | private Disruptor disruptor() {
20 | ThreadFactory producerFactory = Executors.defaultThreadFactory();
21 | BaseEventFactory eventFactory = new BaseEventFactory();
22 | int bufferSize = 1024;
23 | Disruptor disruptor = new Disruptor<>(eventFactory, bufferSize, producerFactory,
24 | ProducerType.SINGLE, new BlockingWaitStrategy());
25 | //两个消费者,任何消息都会同时被两个消费者消费,消费者会根据type来判断哪个是该自己处理的
26 | disruptor.handleEventsWith(new DisruptorServerHandler(), new DisruptorClientHandler());
27 |
28 | disruptor.start();
29 |
30 | return disruptor;
31 | }
32 |
33 | @Bean
34 | public MessageProducer messageProducer() {
35 | return new DisruptorProducer(disruptor());
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/block/src/main/java/com/magiccube/blockchain/socket/distruptor/DisruptorProducer.java:
--------------------------------------------------------------------------------
1 | package com.magiccube.blockchain.socket.distruptor;
2 |
3 | import com.lmax.disruptor.RingBuffer;
4 | import com.lmax.disruptor.dsl.Disruptor;
5 | import com.magiccube.blockchain.socket.distruptor.base.BaseEvent;
6 | import com.magiccube.blockchain.socket.distruptor.base.MessageProducer;
7 |
8 | /**
9 | * 所有客户端、server端发来的消息,都进入这里,然后publish出去,供消费者消费
10 | */
11 | public class DisruptorProducer implements MessageProducer {
12 | private Disruptor disruptor;
13 |
14 | public DisruptorProducer(Disruptor disruptor) {
15 | this.disruptor = disruptor;
16 | }
17 |
18 | @Override
19 | public void publish(BaseEvent baseEvent) {
20 | RingBuffer ringBuffer = disruptor.getRingBuffer();
21 | long sequence = ringBuffer.next();
22 | try {
23 | // Get the entry in the Disruptor
24 | BaseEvent event = ringBuffer.get(sequence);
25 | // for the sequence // Fill with data
26 | event.setBlockPacket(baseEvent.getBlockPacket());
27 | event.setChannelContext(baseEvent.getChannelContext());
28 | } finally {
29 | ringBuffer.publish(sequence);
30 | }
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/block/src/main/java/com/magiccube/blockchain/socket/distruptor/DisruptorServerConsumer.java:
--------------------------------------------------------------------------------
1 | package com.magiccube.blockchain.socket.distruptor;
2 |
3 | import com.magiccube.blockchain.socket.distruptor.base.BaseEvent;
4 | import com.magiccube.blockchain.socket.distruptor.base.MessageConsumer;
5 | import com.magiccube.blockchain.socket.base.AbstractBlockHandler;
6 | import com.magiccube.blockchain.socket.handler.server.*;
7 | import com.magiccube.blockchain.socket.packet.BlockPacket;
8 | import com.magiccube.blockchain.socket.packet.PacketType;
9 | import org.springframework.stereotype.Component;
10 |
11 | import java.util.HashMap;
12 | import java.util.Map;
13 |
14 | /**
15 | * 所有client发来的消息都在这里处理
16 | */
17 | @Component
18 | public class DisruptorServerConsumer implements MessageConsumer {
19 |
20 | private static Map> handlerMap = new HashMap<>();
21 |
22 | static {
23 | handlerMap.put(PacketType.GENERATE_COMPLETE_REQUEST, new GenerateCompleteRequestHandler());
24 | handlerMap.put(PacketType.GENERATE_BLOCK_REQUEST, new GenerateBlockRequestHandler());
25 | handlerMap.put(PacketType.TOTAL_BLOCK_INFO_REQUEST, new TotalBlockInfoRequestHandler());
26 | handlerMap.put(PacketType.FETCH_BLOCK_INFO_REQUEST, new FetchBlockRequestHandler());
27 | handlerMap.put(PacketType.HEART_BEAT, new HeartBeatHandler());
28 | handlerMap.put(PacketType.NEXT_BLOCK_INFO_REQUEST, new NextBlockRequestHandler());
29 | handlerMap.put(PacketType.PBFT_VOTE, new PbftVoteHandler());
30 | }
31 |
32 | @Override
33 | public void receive(BaseEvent baseEvent) throws Exception {
34 | BlockPacket blockPacket = baseEvent.getBlockPacket();
35 | Byte type = blockPacket.getType();
36 | AbstractBlockHandler> handler = handlerMap.get(type);
37 | if (handler == null) {
38 | return;
39 | }
40 | handler.handler(blockPacket, baseEvent.getChannelContext());
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/block/src/main/java/com/magiccube/blockchain/socket/distruptor/DisruptorServerHandler.java:
--------------------------------------------------------------------------------
1 | package com.magiccube.blockchain.socket.distruptor;
2 |
3 | import org.slf4j.Logger;
4 | import org.slf4j.LoggerFactory;
5 |
6 | import com.lmax.disruptor.EventHandler;
7 | import com.magiccube.blockchain.ApplicationContextProvider;
8 | import com.magiccube.blockchain.socket.distruptor.base.BaseEvent;
9 | import com.magiccube.blockchain.socket.handler.server.PbftVoteHandler;
10 |
11 |
12 | public class DisruptorServerHandler implements EventHandler {
13 |
14 | private Logger logger = LoggerFactory.getLogger(DisruptorServerHandler.class);
15 |
16 | @Override
17 | public void onEvent(BaseEvent baseEvent, long sequence, boolean endOfBatch) throws Exception {
18 | try {
19 | ApplicationContextProvider.getBean(DisruptorServerConsumer.class).receive(baseEvent);
20 | } catch (Exception e) {
21 | logger.error("Disruptor事件执行异常",e);
22 | }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/block/src/main/java/com/magiccube/blockchain/socket/distruptor/base/BaseEvent.java:
--------------------------------------------------------------------------------
1 | package com.magiccube.blockchain.socket.distruptor.base;
2 |
3 | import com.magiccube.blockchain.socket.packet.BlockPacket;
4 | import org.tio.core.ChannelContext;
5 |
6 | import java.io.Serializable;
7 |
8 | public class BaseEvent implements Serializable {
9 | private BlockPacket blockPacket;
10 | private ChannelContext channelContext;
11 |
12 | public BaseEvent(BlockPacket blockPacket, ChannelContext channelContext) {
13 | this.blockPacket = blockPacket;
14 | this.channelContext = channelContext;
15 | }
16 |
17 | public BaseEvent(BlockPacket blockPacket) {
18 | this.blockPacket = blockPacket;
19 | }
20 |
21 | public BaseEvent() {
22 | }
23 |
24 | public ChannelContext getChannelContext() {
25 | return channelContext;
26 | }
27 |
28 | public void setChannelContext(ChannelContext channelContext) {
29 | this.channelContext = channelContext;
30 | }
31 |
32 | public BlockPacket getBlockPacket() {
33 | return blockPacket;
34 | }
35 |
36 | public void setBlockPacket(BlockPacket blockPacket) {
37 | this.blockPacket = blockPacket;
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/block/src/main/java/com/magiccube/blockchain/socket/distruptor/base/BaseEventFactory.java:
--------------------------------------------------------------------------------
1 | package com.magiccube.blockchain.socket.distruptor.base;
2 |
3 | import com.lmax.disruptor.EventFactory;
4 |
5 |
6 | public class BaseEventFactory implements EventFactory {
7 | @Override
8 | public BaseEvent newInstance() {
9 | return new BaseEvent();
10 | }
11 |
12 | }
13 |
--------------------------------------------------------------------------------
/block/src/main/java/com/magiccube/blockchain/socket/distruptor/base/MessageConsumer.java:
--------------------------------------------------------------------------------
1 | package com.magiccube.blockchain.socket.distruptor.base;
2 |
3 |
4 | public interface MessageConsumer {
5 | void receive(BaseEvent baseEvent) throws Exception;
6 | }
7 |
--------------------------------------------------------------------------------
/block/src/main/java/com/magiccube/blockchain/socket/distruptor/base/MessageProducer.java:
--------------------------------------------------------------------------------
1 | package com.magiccube.blockchain.socket.distruptor.base;
2 |
3 |
4 | public interface MessageProducer {
5 | void publish(BaseEvent baseEvent);
6 | }
7 |
--------------------------------------------------------------------------------
/block/src/main/java/com/magiccube/blockchain/socket/handler/client/FetchBlockResponseHandler.java:
--------------------------------------------------------------------------------
1 | package com.magiccube.blockchain.socket.handler.client;
2 |
3 | import com.magiccube.blockchain.ApplicationContextProvider;
4 | import com.magiccube.blockchain.block.Block;
5 | import com.magiccube.blockchain.block.check.CheckerManager;
6 | import com.magiccube.blockchain.core.event.AddBlockEvent;
7 | import com.magiccube.blockchain.socket.base.AbstractBlockHandler;
8 | import com.magiccube.blockchain.socket.body.RpcBlockBody;
9 | import com.magiccube.blockchain.socket.body.RpcCheckBlockBody;
10 | import com.magiccube.blockchain.socket.client.PacketSender;
11 | import com.magiccube.blockchain.socket.packet.BlockPacket;
12 | import com.magiccube.blockchain.socket.packet.NextBlockPacketBuilder;
13 | import com.magiccube.blockchain.socket.pbft.queue.NextBlockQueue;
14 |
15 | import org.slf4j.Logger;
16 | import org.slf4j.LoggerFactory;
17 | import org.tio.core.ChannelContext;
18 | import org.tio.utils.json.Json;
19 |
20 | /**
21 | * 对方根据我们传的hash,给我们返回的block
22 | */
23 | public class FetchBlockResponseHandler extends AbstractBlockHandler {
24 | private Logger logger = LoggerFactory.getLogger(TotalBlockInfoResponseHandler.class);
25 |
26 | @Override
27 | public Class bodyClass() {
28 | return RpcBlockBody.class;
29 | }
30 |
31 | @Override
32 | public Object handler(BlockPacket packet, RpcBlockBody rpcBlockBody, ChannelContext channelContext) {
33 | logger.info("收到来自于<" + rpcBlockBody.getAppId() + ">的回复,Block为:" + Json.toJson(rpcBlockBody));
34 |
35 | Block block = rpcBlockBody.getBlock();
36 | //如果为null,说明对方也没有该Block
37 | if (block == null) {
38 | logger.info("对方也没有该Block");
39 | } else {
40 | //此处校验传过来的block的合法性,如果合法,则更新到本地,作为next区块
41 | if(ApplicationContextProvider.getBean(NextBlockQueue.class).pop(block.getHash()) == null) return null;
42 |
43 | CheckerManager checkerManager = ApplicationContextProvider.getBean(CheckerManager.class);
44 | RpcCheckBlockBody rpcCheckBlockBody = checkerManager.check(block);
45 | //校验通过,则存入本地DB,保存新区块
46 | if (rpcCheckBlockBody.getCode() == 0) {
47 | ApplicationContextProvider.publishEvent(new AddBlockEvent(block));
48 | //继续请求下一块
49 | BlockPacket blockPacket = NextBlockPacketBuilder.build();
50 | ApplicationContextProvider.getBean(PacketSender.class).sendGroup(blockPacket);
51 | }
52 | }
53 |
54 | return null;
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/block/src/main/java/com/magiccube/blockchain/socket/handler/client/NextBlockResponseHandler.java:
--------------------------------------------------------------------------------
1 | package com.magiccube.blockchain.socket.handler.client;
2 |
3 | import com.magiccube.blockchain.ApplicationContextProvider;
4 | import com.magiccube.blockchain.socket.base.AbstractBlockHandler;
5 | import com.magiccube.blockchain.socket.body.BlockHash;
6 | import com.magiccube.blockchain.socket.body.RpcNextBlockBody;
7 | import com.magiccube.blockchain.socket.packet.BlockPacket;
8 | import com.magiccube.blockchain.socket.pbft.queue.NextBlockQueue;
9 | import org.slf4j.Logger;
10 | import org.slf4j.LoggerFactory;
11 | import org.tio.core.ChannelContext;
12 |
13 | /**
14 | * 对方根据我们传的hash,给我们返回的next block
15 | */
16 | public class NextBlockResponseHandler extends AbstractBlockHandler {
17 | private Logger logger = LoggerFactory.getLogger(TotalBlockInfoResponseHandler.class);
18 |
19 | @Override
20 | public Class bodyClass() {
21 | return RpcNextBlockBody.class;
22 | }
23 |
24 | @Override
25 | public Object handler(BlockPacket packet, RpcNextBlockBody rpcBlockBody, ChannelContext channelContext) {
26 | logger.info("收到来自于<" + rpcBlockBody.getAppId() + ">的回复,下一个Block hash为:" + rpcBlockBody.getHash());
27 |
28 | String hash = rpcBlockBody.getHash();
29 | //如果为null,说明对方根据我们传过去的hash,找不到next block。说明要么已经是最新了,要么对方的block比自己的少
30 | if (hash == null) {
31 | logger.info("和<" + rpcBlockBody.getAppId() + ">相比,本地已是最新块了");
32 | } else {
33 | BlockHash blockHash = new BlockHash(hash, rpcBlockBody.getPrevHash(), rpcBlockBody.getAppId());
34 | //此处进行搜集next block的hash,相同的hash过2f+1时可以确认
35 | ApplicationContextProvider.getBean(NextBlockQueue.class).push(blockHash);
36 | }
37 |
38 | return null;
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/block/src/main/java/com/magiccube/blockchain/socket/handler/client/TotalBlockInfoResponseHandler.java:
--------------------------------------------------------------------------------
1 | package com.magiccube.blockchain.socket.handler.client;
2 |
3 | import com.magiccube.blockchain.socket.base.AbstractBlockHandler;
4 | import com.magiccube.blockchain.socket.body.RpcBlockBody;
5 | import com.magiccube.blockchain.socket.packet.BlockPacket;
6 | import org.slf4j.Logger;
7 | import org.slf4j.LoggerFactory;
8 | import org.tio.core.ChannelContext;
9 | import org.tio.utils.json.Json;
10 |
11 | /**
12 | * 对获取所有区块信息请求的回复
13 | */
14 | public class TotalBlockInfoResponseHandler extends AbstractBlockHandler {
15 | private Logger logger = LoggerFactory.getLogger(TotalBlockInfoResponseHandler.class);
16 |
17 | @Override
18 | public Class bodyClass() {
19 | return RpcBlockBody.class;
20 | }
21 |
22 | @Override
23 | public Object handler(BlockPacket packet, RpcBlockBody rpcBlockBody, ChannelContext channelContext) throws Exception {
24 | logger.info("收到<请求生成Block的回应>消息", Json.toJson(rpcBlockBody));
25 |
26 | //TODO check合法性
27 | //TODO response
28 |
29 | return null;
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/block/src/main/java/com/magiccube/blockchain/socket/handler/server/FetchBlockRequestHandler.java:
--------------------------------------------------------------------------------
1 | package com.magiccube.blockchain.socket.handler.server;
2 |
3 | import com.magiccube.blockchain.ApplicationContextProvider;
4 | import com.magiccube.blockchain.block.Block;
5 | import com.magiccube.blockchain.core.manager.DbBlockManager;
6 | import com.magiccube.blockchain.socket.base.AbstractBlockHandler;
7 | import com.magiccube.blockchain.socket.body.RpcBlockBody;
8 | import com.magiccube.blockchain.socket.body.RpcSimpleBlockBody;
9 | import com.magiccube.blockchain.socket.packet.BlockPacket;
10 | import com.magiccube.blockchain.socket.packet.PacketBuilder;
11 | import com.magiccube.blockchain.socket.packet.PacketType;
12 | import org.slf4j.Logger;
13 | import org.slf4j.LoggerFactory;
14 | import org.tio.core.Aio;
15 | import org.tio.core.ChannelContext;
16 |
17 | /**
18 | * 请求别人某个区块的信息
19 | */
20 | public class FetchBlockRequestHandler extends AbstractBlockHandler {
21 | private Logger logger = LoggerFactory.getLogger(FetchBlockRequestHandler.class);
22 |
23 | @Override
24 | public Class bodyClass() {
25 | return RpcSimpleBlockBody.class;
26 | }
27 |
28 | @Override
29 | public Object handler(BlockPacket packet, RpcSimpleBlockBody rpcBlockBody, ChannelContext channelContext) {
30 | logger.info("收到来自于<" + rpcBlockBody.getAppId() + "><请求该Block>消息,block hash为[" + rpcBlockBody.getHash() + "]");
31 | Block block = ApplicationContextProvider.getBean(DbBlockManager.class).getBlockByHash(rpcBlockBody.getHash());
32 |
33 | BlockPacket blockPacket = new PacketBuilder<>().setType(PacketType.FETCH_BLOCK_INFO_RESPONSE).setBody(new
34 | RpcBlockBody(block)).build();
35 | Aio.send(channelContext, blockPacket);
36 |
37 | return null;
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/block/src/main/java/com/magiccube/blockchain/socket/handler/server/GenerateBlockRequestHandler.java:
--------------------------------------------------------------------------------
1 | package com.magiccube.blockchain.socket.handler.server;
2 |
3 | import com.magiccube.blockchain.ApplicationContextProvider;
4 | import com.magiccube.blockchain.block.Block;
5 | import com.magiccube.blockchain.block.check.CheckerManager;
6 | import com.magiccube.blockchain.socket.base.AbstractBlockHandler;
7 | import com.magiccube.blockchain.socket.body.RpcBlockBody;
8 | import com.magiccube.blockchain.socket.body.RpcCheckBlockBody;
9 | import com.magiccube.blockchain.socket.packet.BlockPacket;
10 | import com.magiccube.blockchain.socket.pbft.VoteType;
11 | import com.magiccube.blockchain.socket.pbft.msg.VotePreMsg;
12 | import com.magiccube.blockchain.socket.pbft.queue.MsgQueueManager;
13 | import org.slf4j.Logger;
14 | import org.slf4j.LoggerFactory;
15 | import org.tio.core.ChannelContext;
16 |
17 | /**
18 | * 收到请求生成区块消息,进入PrePre队列
19 | */
20 | public class GenerateBlockRequestHandler extends AbstractBlockHandler {
21 | private Logger logger = LoggerFactory.getLogger(GenerateBlockRequestHandler.class);
22 |
23 |
24 | @Override
25 | public Class bodyClass() {
26 | return RpcBlockBody.class;
27 | }
28 |
29 | @Override
30 | public Object handler(BlockPacket packet, RpcBlockBody rpcBlockBody, ChannelContext channelContext) {
31 | Block block = rpcBlockBody.getBlock();
32 | logger.info("收到来自于<" + rpcBlockBody.getAppId() + "><请求生成Block>消息,block信息为[" + block + "]");
33 |
34 | CheckerManager checkerManager = ApplicationContextProvider.getBean(CheckerManager.class);
35 | //对区块的基本信息进行校验,校验通过后进入pbft的Pre队列
36 | RpcCheckBlockBody rpcCheckBlockBody = checkerManager.check(block);
37 | logger.info("校验结果:" + rpcCheckBlockBody.toString());
38 | if (rpcCheckBlockBody.getCode() == 0) {
39 | VotePreMsg votePreMsg = new VotePreMsg();
40 | votePreMsg.setBlock(block);
41 | votePreMsg.setVoteType(VoteType.PREPREPARE);
42 | votePreMsg.setNumber(block.getBlockHeader().getNumber());
43 | votePreMsg.setAppId(rpcBlockBody.getAppId());
44 | votePreMsg.setHash(block.getHash());
45 | votePreMsg.setAgree(true);
46 | //将消息推入PrePrepare队列
47 | ApplicationContextProvider.getBean(MsgQueueManager.class).pushMsg(votePreMsg);
48 | }
49 |
50 | return null;
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/block/src/main/java/com/magiccube/blockchain/socket/handler/server/GenerateCompleteRequestHandler.java:
--------------------------------------------------------------------------------
1 | package com.magiccube.blockchain.socket.handler.server;
2 |
3 | import org.slf4j.Logger;
4 | import org.slf4j.LoggerFactory;
5 | import org.tio.core.ChannelContext;
6 |
7 | import com.magiccube.blockchain.ApplicationContextProvider;
8 | import com.magiccube.blockchain.block.Block;
9 | import com.magiccube.blockchain.common.timer.TimerManager;
10 | import com.magiccube.blockchain.core.manager.DbBlockManager;
11 | import com.magiccube.blockchain.socket.base.AbstractBlockHandler;
12 | import com.magiccube.blockchain.socket.body.RpcSimpleBlockBody;
13 | import com.magiccube.blockchain.socket.client.PacketSender;
14 | import com.magiccube.blockchain.socket.packet.BlockPacket;
15 | import com.magiccube.blockchain.socket.packet.NextBlockPacketBuilder;
16 |
17 | /**
18 | * 已生成了新区块的全网广播
19 | */
20 | public class GenerateCompleteRequestHandler extends AbstractBlockHandler {
21 | private Logger logger = LoggerFactory.getLogger(GenerateCompleteRequestHandler.class);
22 |
23 | @Override
24 | public Class bodyClass() {
25 | return RpcSimpleBlockBody.class;
26 | }
27 |
28 | @Override
29 | public Object handler(BlockPacket packet, RpcSimpleBlockBody rpcBlockBody, ChannelContext channelContext) {
30 | logger.info("收到来自于<" + rpcBlockBody.getAppId() + "><生成了新的Block>消息,block hash为[" + rpcBlockBody.getHash() +
31 | "]");
32 |
33 | //延迟2秒校验一下本地是否有该区块,如果没有,则发请求去获取新Block
34 | //延迟的目的是可能刚好自己也马上就要生成同样的Block了,就可以省一次请求
35 | TimerManager.schedule(() -> {
36 | Block block = ApplicationContextProvider.getBean(DbBlockManager.class).getBlockByHash(rpcBlockBody
37 | .getHash());
38 | //本地有了
39 | if (block == null) {
40 | logger.info("开始去获取别人的新区块");
41 | //在这里发请求,去获取group别人的新区块
42 | BlockPacket nextBlockPacket = NextBlockPacketBuilder.build();
43 | ApplicationContextProvider.getBean(PacketSender.class).sendGroup(nextBlockPacket);
44 | }
45 | return null;
46 | },2000);
47 |
48 | return null;
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/block/src/main/java/com/magiccube/blockchain/socket/handler/server/HeartBeatHandler.java:
--------------------------------------------------------------------------------
1 | package com.magiccube.blockchain.socket.handler.server;
2 |
3 | import com.magiccube.blockchain.socket.base.AbstractBlockHandler;
4 | import com.magiccube.blockchain.socket.body.HeartBeatBody;
5 | import com.magiccube.blockchain.socket.packet.BlockPacket;
6 | import org.slf4j.Logger;
7 | import org.slf4j.LoggerFactory;
8 | import org.tio.core.ChannelContext;
9 |
10 | /**
11 | * 客户端心跳包
12 | */
13 | @Deprecated
14 | public class HeartBeatHandler extends AbstractBlockHandler {
15 | private Logger logger = LoggerFactory.getLogger(HeartBeatHandler.class);
16 |
17 | @Override
18 | public Class bodyClass() {
19 | return HeartBeatBody.class;
20 | }
21 |
22 | @Override
23 | public Object handler(BlockPacket packet, HeartBeatBody heartBeatBody, ChannelContext channelContext) throws Exception {
24 | logger.info("收到<心跳包>消息", heartBeatBody.getText());
25 |
26 | return null;
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/block/src/main/java/com/magiccube/blockchain/socket/handler/server/NextBlockRequestHandler.java:
--------------------------------------------------------------------------------
1 | package com.magiccube.blockchain.socket.handler.server;
2 |
3 | import com.magiccube.blockchain.ApplicationContextProvider;
4 | import com.magiccube.blockchain.block.Block;
5 | import com.magiccube.blockchain.core.manager.DbBlockManager;
6 | import com.magiccube.blockchain.socket.base.AbstractBlockHandler;
7 | import com.magiccube.blockchain.socket.body.RpcNextBlockBody;
8 | import com.magiccube.blockchain.socket.body.RpcSimpleBlockBody;
9 | import com.magiccube.blockchain.socket.packet.BlockPacket;
10 | import com.magiccube.blockchain.socket.packet.PacketBuilder;
11 | import com.magiccube.blockchain.socket.packet.PacketType;
12 | import org.slf4j.Logger;
13 | import org.slf4j.LoggerFactory;
14 | import org.tio.core.Aio;
15 | import org.tio.core.ChannelContext;
16 | import org.tio.utils.json.Json;
17 |
18 | /**
19 | * 获取某个区块下一块的请求,发起方带着自己的lastBlock hash,接收方则将自己的区块中,在传来的hash后面的那块返回回去。
20 | * 如A传来了3,而我本地有5个区块,则返回区块4。
21 | */
22 | public class NextBlockRequestHandler extends AbstractBlockHandler {
23 | private Logger logger = LoggerFactory.getLogger(TotalBlockInfoRequestHandler.class);
24 |
25 | @Override
26 | public Class bodyClass() {
27 | return RpcSimpleBlockBody.class;
28 | }
29 |
30 | @Override
31 | public Object handler(BlockPacket packet, RpcSimpleBlockBody rpcBlockBody, ChannelContext channelContext) {
32 | logger.info("收到来自于<" + rpcBlockBody.getAppId() + ">的<请求下一Block>消息,请求者的block hash为:" + Json.toJson
33 | (rpcBlockBody.getHash()));
34 | //传来的Block,如果为null,说明发起方连一个Block都没有
35 | String hash = rpcBlockBody.getHash();
36 |
37 | //查询自己的next block hash,返回给对方,让对方搜集2f+1后确定哪个是对的
38 | Block nextBlock = ApplicationContextProvider.getBean(DbBlockManager.class).getNextBlockByHash(hash);
39 | String nextHash = null;
40 | if (nextBlock != null) {
41 | nextHash = nextBlock.getHash();
42 | }
43 | RpcNextBlockBody respBody = new RpcNextBlockBody(nextHash, hash);
44 | respBody.setResponseMsgId(rpcBlockBody.getMessageId());
45 | BlockPacket blockPacket = new PacketBuilder().setType(PacketType
46 | .NEXT_BLOCK_INFO_RESPONSE).setBody(respBody).build();
47 | Aio.send(channelContext, blockPacket);
48 | logger.info("回复给<" + rpcBlockBody.getAppId() + ">,我的nextBlock是" + respBody.toString());
49 |
50 | return null;
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/block/src/main/java/com/magiccube/blockchain/socket/handler/server/PbftVoteHandler.java:
--------------------------------------------------------------------------------
1 | package com.magiccube.blockchain.socket.handler.server;
2 |
3 | import com.magiccube.blockchain.ApplicationContextProvider;
4 | import com.magiccube.blockchain.socket.base.AbstractBlockHandler;
5 | import com.magiccube.blockchain.socket.body.VoteBody;
6 | import com.magiccube.blockchain.socket.packet.BlockPacket;
7 | import com.magiccube.blockchain.socket.pbft.msg.VoteMsg;
8 | import com.magiccube.blockchain.socket.pbft.queue.MsgQueueManager;
9 | import org.slf4j.Logger;
10 | import org.slf4j.LoggerFactory;
11 | import org.tio.core.ChannelContext;
12 |
13 | /**
14 | * pbft投票处理
15 | */
16 | public class PbftVoteHandler extends AbstractBlockHandler {
17 | private Logger logger = LoggerFactory.getLogger(PbftVoteHandler.class);
18 |
19 |
20 | @Override
21 | public Class bodyClass() {
22 | return VoteBody.class;
23 | }
24 |
25 | @Override
26 | public Object handler(BlockPacket packet, VoteBody voteBody, ChannelContext channelContext) {
27 | VoteMsg voteMsg = voteBody.getVoteMsg();
28 | logger.info("收到来自于<" + voteMsg.getAppId() + "><投票>消息,投票信息为[" + voteMsg + "]");
29 |
30 | ApplicationContextProvider.getBean(MsgQueueManager.class).pushMsg(voteMsg);
31 | return null;
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/block/src/main/java/com/magiccube/blockchain/socket/handler/server/TotalBlockInfoRequestHandler.java:
--------------------------------------------------------------------------------
1 | package com.magiccube.blockchain.socket.handler.server;
2 |
3 | import com.magiccube.blockchain.socket.base.AbstractBlockHandler;
4 | import com.magiccube.blockchain.socket.body.RpcBlockBody;
5 | import com.magiccube.blockchain.socket.packet.BlockPacket;
6 | import org.slf4j.Logger;
7 | import org.slf4j.LoggerFactory;
8 | import org.tio.core.ChannelContext;
9 | import org.tio.utils.json.Json;
10 |
11 | /**
12 | * 获取全部区块信息的请求,全网广播
13 | */
14 | public class TotalBlockInfoRequestHandler extends AbstractBlockHandler {
15 | private Logger logger = LoggerFactory.getLogger(TotalBlockInfoRequestHandler.class);
16 |
17 | @Override
18 | public Class bodyClass() {
19 | return RpcBlockBody.class;
20 | }
21 |
22 | @Override
23 | public Object handler(BlockPacket packet, RpcBlockBody rpcBlockBody, ChannelContext channelContext) throws Exception {
24 | logger.info("收到<请求生成Block的回应>消息", Json.toJson(rpcBlockBody));
25 |
26 | //TODO check合法性
27 | //TODO response
28 |
29 | return null;
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/block/src/main/java/com/magiccube/blockchain/socket/packet/BlockPacket.java:
--------------------------------------------------------------------------------
1 | package com.magiccube.blockchain.socket.packet;
2 |
3 | import com.magiccube.blockchain.socket.common.Const;
4 | import org.tio.core.intf.Packet;
5 |
6 | import java.io.UnsupportedEncodingException;
7 |
8 | public class BlockPacket extends Packet {
9 | /**
10 | * 消息头的长度 1+4
11 | */
12 | public static final int HEADER_LENGTH = 5;
13 | /**
14 | * 消息类型,其值在Type中定义
15 | */
16 | private byte type;
17 |
18 | private byte[] body;
19 |
20 | public BlockPacket() {
21 | super();
22 | }
23 |
24 | /**
25 | * @param type type
26 | * @param body body
27 | * @author tanyaowu
28 | */
29 | public BlockPacket(byte type, byte[] body) {
30 | super();
31 | this.type = type;
32 | this.body = body;
33 | }
34 |
35 | public BlockPacket(byte type, String body) {
36 | super();
37 | this.type = type;
38 | setBody(body);
39 | }
40 |
41 | /**
42 | * @return the body
43 | */
44 | public byte[] getBody() {
45 | return body;
46 | }
47 |
48 | /**
49 | * @return the type
50 | */
51 | public byte getType() {
52 | return type;
53 | }
54 |
55 | @Override
56 | public String logstr() {
57 | return "" + type;
58 | }
59 |
60 | /**
61 | * @param body
62 | * the body to set
63 | */
64 | public void setBody(byte[] body) {
65 | this.body = body;
66 | }
67 |
68 | public void setBody(String body) {
69 | try {
70 | this.body = body.getBytes(Const.CHARSET);
71 | } catch (UnsupportedEncodingException e) {
72 | e.printStackTrace();
73 | }
74 | }
75 |
76 | /**
77 | * @param type
78 | * the type to set
79 | */
80 | public void setType(byte type) {
81 | this.type = type;
82 | }
83 | }
84 |
--------------------------------------------------------------------------------
/block/src/main/java/com/magiccube/blockchain/socket/packet/NextBlockPacketBuilder.java:
--------------------------------------------------------------------------------
1 | package com.magiccube.blockchain.socket.packet;
2 |
3 | import com.magiccube.blockchain.ApplicationContextProvider;
4 | import com.magiccube.blockchain.core.event.ClientRequestEvent;
5 | import com.magiccube.blockchain.core.manager.DbBlockManager;
6 | import com.magiccube.blockchain.socket.body.RpcSimpleBlockBody;
7 |
8 | /**
9 | * 构建向别的节点请求next block的builder.带着自己最后一个block的hash
10 | */
11 | public class NextBlockPacketBuilder {
12 | public static BlockPacket build() {
13 | return build(null);
14 | }
15 |
16 | public static BlockPacket build(String responseId) {
17 | String hash = ApplicationContextProvider.getBean(DbBlockManager.class).getLastBlockHash();
18 |
19 | RpcSimpleBlockBody rpcBlockBody = new RpcSimpleBlockBody(hash);
20 | rpcBlockBody.setResponseMsgId(responseId);
21 | BlockPacket blockPacket = new PacketBuilder<>().setType(PacketType.NEXT_BLOCK_INFO_REQUEST).setBody
22 | (rpcBlockBody).build();
23 | //发布client请求事件
24 | ApplicationContextProvider.publishEvent(new ClientRequestEvent(blockPacket));
25 | return blockPacket;
26 | }
27 |
28 | }
29 |
--------------------------------------------------------------------------------
/block/src/main/java/com/magiccube/blockchain/socket/packet/PacketBuilder.java:
--------------------------------------------------------------------------------
1 | package com.magiccube.blockchain.socket.packet;
2 |
3 | import com.magiccube.blockchain.socket.body.BaseBody;
4 | import org.tio.utils.json.Json;
5 |
6 | public class PacketBuilder {
7 | /**
8 | * 消息类型,其值在Type中定义
9 | */
10 | private byte type;
11 |
12 | private T body;
13 |
14 | public PacketBuilder setType(byte type) {
15 | this.type = type;
16 | return this;
17 | }
18 |
19 | public PacketBuilder setBody(T body) {
20 | this.body = body;
21 | return this;
22 | }
23 |
24 | public BlockPacket build() {
25 | return new BlockPacket(type, Json.toJson(body));
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/block/src/main/java/com/magiccube/blockchain/socket/packet/PacketType.java:
--------------------------------------------------------------------------------
1 | package com.magiccube.blockchain.socket.packet;
2 |
3 | /**
4 | * packetType大于0时是请求类型,小于0时为响应类型
5 | */
6 | public interface PacketType {
7 | /**
8 | * 心跳包
9 | */
10 | byte HEART_BEAT = 0;
11 | /**
12 | * 已生成新的区块
13 | */
14 | byte GENERATE_COMPLETE_REQUEST = 1;
15 | /**
16 | * 已生成新的区块回应
17 | */
18 | byte GENERATE_COMPLETE_RESPONSE = -1;
19 | /**
20 | * 请求生成block
21 | */
22 | byte GENERATE_BLOCK_REQUEST = 2;
23 | /**
24 | * 同意、拒绝生成
25 | */
26 | byte GENERATE_BLOCK_RESPONSE = -2;
27 | /**
28 | * 获取所有block信息
29 | */
30 | byte TOTAL_BLOCK_INFO_REQUEST = 3;
31 | /**
32 | * 我的所有块信息
33 | */
34 | byte TOTAL_BLOCK_INFO_RESPONSE = -3;
35 | /**
36 | * 获取一个block信息
37 | */
38 | byte FETCH_BLOCK_INFO_REQUEST = 4;
39 | /**
40 | * 获取一块信息响应
41 | */
42 | byte FETCH_BLOCK_INFO_RESPONSE = -4;
43 | /**
44 | * 获取下一个区块的信息
45 | */
46 | byte NEXT_BLOCK_INFO_REQUEST = 5;
47 | /**
48 | * 获取下一个区块的信息
49 | */
50 | byte NEXT_BLOCK_INFO_RESPONSE = -5;
51 | /**
52 | * pbft投票
53 | */
54 | byte PBFT_VOTE = 10;
55 | }
56 |
--------------------------------------------------------------------------------
/block/src/main/java/com/magiccube/blockchain/socket/pbft/VoteType.java:
--------------------------------------------------------------------------------
1 | package com.magiccube.blockchain.socket.pbft;
2 |
3 | /**
4 | * pbft算法的各状态
5 | *
6 | * 算法流程如下:
7 | *
8 | * 当前时间片的锻造者将收集到的交易打包成block并进行广播(这一步与之前的算法一致)
9 | * 收到block的委托人节点如果还没有收到过这个block并且验证合法后,就广播一个prepare消息,其中h为block的高度,d是block的摘要,s是本节点签名
10 | * 收到prepare消息后,节点开始在内存中累加消息数量,当收到超过f+1不同节点的prepare消息后,节点进入prepared状态,之后会广播一个commit消息
11 | * 每个节点收到超过2f+1个不同节点的commit消息后,就认为该区块已经达成一致,进入committed状态,并将其持久化到区块链数据库中
12 | * 系统在在收到第一个高度为h的block时,启动一个定时器,当定时到期后,如果还没达成一致,就放弃本次共识。
13 | */
14 | public class VoteType {
15 | /**
16 | * 节点自己打算生成Block
17 | */
18 | public static final byte PREPREPARE = 1;
19 | /**
20 | * 节点收到请求生成block消息,进入准备状态,对外广播该状态
21 | */
22 | public static final byte PREPARE = 2;
23 | /**
24 | * 每个节点收到超过2f+1个不同节点的commit消息后,就认为该区块已经达成一致,进入committed状态,并将其持久化到区块链数据库中
25 | */
26 | public static final byte COMMIT = 3;
27 | }
28 |
--------------------------------------------------------------------------------
/block/src/main/java/com/magiccube/blockchain/socket/pbft/event/MsgCommitEvent.java:
--------------------------------------------------------------------------------
1 | package com.magiccube.blockchain.socket.pbft.event;
2 |
3 | import com.magiccube.blockchain.socket.pbft.msg.VoteMsg;
4 | import org.springframework.context.ApplicationEvent;
5 |
6 | /**
7 | * 消息已被验证,进入到Commit集合中
8 | */
9 | public class MsgCommitEvent extends ApplicationEvent {
10 | public MsgCommitEvent(VoteMsg source) {
11 | super(source);
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/block/src/main/java/com/magiccube/blockchain/socket/pbft/event/MsgPrepareEvent.java:
--------------------------------------------------------------------------------
1 | package com.magiccube.blockchain.socket.pbft.event;
2 |
3 | import com.magiccube.blockchain.socket.pbft.msg.VoteMsg;
4 | import org.springframework.context.ApplicationEvent;
5 |
6 | /**
7 | * 消息已被验证,进入到Prepare集合中
8 | */
9 | public class MsgPrepareEvent extends ApplicationEvent {
10 | public MsgPrepareEvent(VoteMsg source) {
11 | super(source);
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/block/src/main/java/com/magiccube/blockchain/socket/pbft/listener/CommitEventListener.java:
--------------------------------------------------------------------------------
1 | package com.magiccube.blockchain.socket.pbft.listener;
2 |
3 | import com.magiccube.blockchain.socket.body.VoteBody;
4 | import com.magiccube.blockchain.socket.client.PacketSender;
5 | import com.magiccube.blockchain.socket.packet.BlockPacket;
6 | import com.magiccube.blockchain.socket.packet.PacketBuilder;
7 | import com.magiccube.blockchain.socket.packet.PacketType;
8 | import com.magiccube.blockchain.socket.pbft.event.MsgCommitEvent;
9 | import com.magiccube.blockchain.socket.pbft.msg.VoteMsg;
10 | import org.springframework.context.event.EventListener;
11 | import org.springframework.stereotype.Component;
12 |
13 | import javax.annotation.Resource;
14 |
15 | /**
16 | * 监听block可以commit消息
17 | */
18 | @Component
19 | public class CommitEventListener {
20 | @Resource
21 | private PacketSender packetSender;
22 |
23 | /**
24 | * block已经开始进入commit状态,广播消息
25 | *
26 | * @param msgCommitEvent
27 | * msgCommitEvent
28 | */
29 | @EventListener
30 | public void msgIsCommit(MsgCommitEvent msgCommitEvent) {
31 | VoteMsg voteMsg = (VoteMsg) msgCommitEvent.getSource();
32 |
33 | //群发消息,通知所有节点,我已对该Block Prepare
34 | BlockPacket blockPacket = new PacketBuilder<>().setType(PacketType.PBFT_VOTE).setBody(new
35 | VoteBody(voteMsg)).build();
36 |
37 | //广播给所有人我已commit
38 | packetSender.sendGroup(blockPacket);
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/block/src/main/java/com/magiccube/blockchain/socket/pbft/listener/PrepareEventListener.java:
--------------------------------------------------------------------------------
1 | package com.magiccube.blockchain.socket.pbft.listener;
2 |
3 | import javax.annotation.Resource;
4 |
5 | import org.springframework.context.event.EventListener;
6 | import org.springframework.stereotype.Component;
7 |
8 | import com.magiccube.blockchain.socket.body.VoteBody;
9 | import com.magiccube.blockchain.socket.client.PacketSender;
10 | import com.magiccube.blockchain.socket.packet.BlockPacket;
11 | import com.magiccube.blockchain.socket.packet.PacketBuilder;
12 | import com.magiccube.blockchain.socket.packet.PacketType;
13 | import com.magiccube.blockchain.socket.pbft.event.MsgPrepareEvent;
14 | import com.magiccube.blockchain.socket.pbft.msg.VoteMsg;
15 |
16 |
17 | @Component
18 | public class PrepareEventListener {
19 | @Resource
20 | private PacketSender packetSender;
21 |
22 | /**
23 | * block已经开始进入Prepare状态
24 | *
25 | * @param msgPrepareEvent
26 | * msgIsPrepareEvent
27 | */
28 | @EventListener
29 | public void msgIsPrepare(MsgPrepareEvent msgPrepareEvent) {
30 | VoteMsg voteMsg = (VoteMsg) msgPrepareEvent.getSource();
31 |
32 | //群发消息,通知别的节点,我已对该Block Prepare
33 | BlockPacket blockPacket = new PacketBuilder<>().setType(PacketType.PBFT_VOTE).setBody(new
34 | VoteBody(voteMsg)).build();
35 |
36 | //广播给所有人我已Prepare
37 | packetSender.sendGroup(blockPacket);
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/block/src/main/java/com/magiccube/blockchain/socket/pbft/msg/VoteMsg.java:
--------------------------------------------------------------------------------
1 | package com.magiccube.blockchain.socket.pbft.msg;
2 |
3 | /**
4 | * pbft算法传输prepare和commit消息的载体
5 | */
6 | public class VoteMsg {
7 | /**
8 | * 当前投票状态(Prepare,commit)
9 | */
10 | private byte voteType;
11 | /**
12 | * 区块的hash
13 | */
14 | private String hash;
15 | /**
16 | * 区块的number
17 | */
18 | private int number;
19 | /**
20 | * 是哪个节点传来的
21 | */
22 | private String appId;
23 | /**
24 | * 是否同意
25 | */
26 | private boolean agree;
27 |
28 | @Override
29 | public String toString() {
30 | return "VoteMsg{" +
31 | "voteType=" + voteType +
32 | ", hash='" + hash + '\'' +
33 | ", number=" + number +
34 | ", appId='" + appId + '\'' +
35 | ", agree=" + agree +
36 | '}';
37 | }
38 |
39 | public byte getVoteType() {
40 | return voteType;
41 | }
42 |
43 | public void setVoteType(byte voteType) {
44 | this.voteType = voteType;
45 | }
46 |
47 | public String getHash() {
48 | return hash;
49 | }
50 |
51 | public void setHash(String hash) {
52 | this.hash = hash;
53 | }
54 |
55 | public int getNumber() {
56 | return number;
57 | }
58 |
59 | public void setNumber(int number) {
60 | this.number = number;
61 | }
62 |
63 | public String getAppId() {
64 | return appId;
65 | }
66 |
67 | public void setAppId(String appId) {
68 | this.appId = appId;
69 | }
70 |
71 | public boolean isAgree() {
72 | return agree;
73 | }
74 |
75 | public void setAgree(boolean agree) {
76 | this.agree = agree;
77 | }
78 | }
79 |
--------------------------------------------------------------------------------
/block/src/main/java/com/magiccube/blockchain/socket/pbft/msg/VotePreMsg.java:
--------------------------------------------------------------------------------
1 | package com.magiccube.blockchain.socket.pbft.msg;
2 |
3 | import com.magiccube.blockchain.block.Block;
4 |
5 |
6 | public class VotePreMsg extends VoteMsg {
7 | private Block block;
8 |
9 | public Block getBlock() {
10 | return block;
11 | }
12 |
13 | public void setBlock(Block block) {
14 | this.block = block;
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/block/src/main/java/com/magiccube/blockchain/socket/pbft/queue/AbstractVoteMsgQueue.java:
--------------------------------------------------------------------------------
1 | package com.magiccube.blockchain.socket.pbft.queue;
2 |
3 | import java.util.ArrayList;
4 | import java.util.List;
5 | import java.util.concurrent.ConcurrentHashMap;
6 |
7 | import org.slf4j.Logger;
8 | import org.slf4j.LoggerFactory;
9 |
10 | import com.magiccube.blockchain.common.timer.TimerManager;
11 | import com.magiccube.blockchain.socket.pbft.msg.VoteMsg;
12 |
13 | import cn.hutool.core.collection.CollectionUtil;
14 |
15 | public abstract class AbstractVoteMsgQueue extends BaseMsgQueue {
16 | /**
17 | * 存储所有的hash的投票集合
18 | */
19 | protected ConcurrentHashMap> voteMsgConcurrentHashMap = new ConcurrentHashMap<>();
20 | /**
21 | * 存储本节点已确认状态的hash的集合,即本节点已对外广播过允许commit或拒绝commit的消息了
22 | */
23 | protected ConcurrentHashMap voteStateConcurrentHashMap = new ConcurrentHashMap<>();
24 |
25 | private Logger logger = LoggerFactory.getLogger(getClass());
26 |
27 | abstract void deal(VoteMsg voteMsg, List voteMsgs);
28 |
29 | @Override
30 | protected void push(VoteMsg voteMsg) {
31 | String hash = voteMsg.getHash();
32 | List voteMsgs = voteMsgConcurrentHashMap.get(hash);
33 | if (CollectionUtil.isEmpty(voteMsgs)) {
34 | voteMsgs = new ArrayList<>();
35 | voteMsgConcurrentHashMap.put(hash, voteMsgs);
36 | } else {
37 | //如果不空的情况下,判断本地集合是否已经存在完全相同的voteMsg了
38 | for (VoteMsg temp : voteMsgs) {
39 | if (temp.getAppId().equals(voteMsg.getAppId())) {
40 | return;
41 | }
42 | }
43 | }
44 |
45 | //添加进去
46 | voteMsgs.add(voteMsg);
47 | //如果已经对该hash投过票了,就不再继续
48 | if (voteStateConcurrentHashMap.get(hash) != null) {
49 | return;
50 | }
51 |
52 | deal(voteMsg, voteMsgs);
53 | }
54 |
55 | /**
56 | * 该方法用来确认待push阶段的下一阶段是否已存在已达成共识的Block
57 | * 譬如收到了区块5的Prepare的投票信息,那么我是否接受该投票,需要先校验Commit阶段是否已经存在number>=5的投票成功信息
58 | *
59 | * @param hash
60 | * hash
61 | * @return 是否超过
62 | */
63 | public boolean hasOtherConfirm(String hash, int number) {
64 | //遍历该阶段的所有投票信息
65 | for (String key : voteMsgConcurrentHashMap.keySet()) {
66 | //如果下一阶段存在同一个hash的投票,则不理会
67 | if (hash.equals(key)) {
68 | continue;
69 | }
70 | //如果下一阶段的number比当前投票的小,则不理会
71 | if (voteMsgConcurrentHashMap.get(key).get(0).getNumber() < number) {
72 | continue;
73 | }
74 | //只有别的>=number的Block已经达成共识了,则返回true,那么将会拒绝该hash进入下一阶段
75 | if (voteStateConcurrentHashMap.get(key) != null && voteStateConcurrentHashMap.get(key)) {
76 | return true;
77 | }
78 | }
79 | return false;
80 | }
81 |
82 | /**
83 | * 清理旧的block的hash
84 | */
85 | protected void clearOldBlockHash(int number) {
86 | TimerManager.schedule(() -> {
87 | for (String key : voteMsgConcurrentHashMap.keySet()) {
88 | if (voteMsgConcurrentHashMap.get(key).get(0).getNumber() <= number) {
89 | voteMsgConcurrentHashMap.remove(key);
90 | voteStateConcurrentHashMap.remove(key);
91 | }
92 | }
93 | return null;
94 | },2000);
95 | }
96 | }
97 |
--------------------------------------------------------------------------------
/block/src/main/java/com/magiccube/blockchain/socket/pbft/queue/BaseMsgQueue.java:
--------------------------------------------------------------------------------
1 | package com.magiccube.blockchain.socket.pbft.queue;
2 |
3 | import com.magiccube.blockchain.socket.client.ClientStarter;
4 | import com.magiccube.blockchain.socket.pbft.msg.VoteMsg;
5 | import org.springframework.stereotype.Component;
6 |
7 | import javax.annotation.Resource;
8 |
9 | /**
10 | * 各节点互传的投票消息存储队列基类
11 | */
12 | @Component
13 | public abstract class BaseMsgQueue {
14 | @Resource
15 | private ClientStarter clientStarter;
16 |
17 | public int pbftSize() {
18 | return clientStarter.pbftSize();
19 | }
20 |
21 | public int pbftAgreeSize() {
22 | return clientStarter.pbftAgreeCount();
23 | }
24 | /**
25 | * 来了新消息
26 | *
27 | * @param voteMsg
28 | * voteMsg
29 | */
30 | protected abstract void push(VoteMsg voteMsg);
31 | }
32 |
--------------------------------------------------------------------------------
/block/src/main/java/com/magiccube/blockchain/socket/pbft/queue/CommitMsgQueue.java:
--------------------------------------------------------------------------------
1 | package com.magiccube.blockchain.socket.pbft.queue;
2 |
3 | import java.util.List;
4 |
5 | import javax.annotation.Resource;
6 |
7 | import org.slf4j.Logger;
8 | import org.slf4j.LoggerFactory;
9 | import org.springframework.context.event.EventListener;
10 | import org.springframework.core.annotation.Order;
11 | import org.springframework.stereotype.Component;
12 |
13 | import com.magiccube.blockchain.ApplicationContextProvider;
14 | import com.magiccube.blockchain.block.Block;
15 | import com.magiccube.blockchain.core.event.AddBlockEvent;
16 | import com.magiccube.blockchain.socket.pbft.msg.VoteMsg;
17 |
18 | /**
19 | * Confirm阶段的消息队列
20 | * 每个节点收到超过2f+1个不同节点(包括自己)的commit消息后,就认为该区块已经达成一致,进入committed状态,并将其持久化到区块链数据库中
21 | */
22 | @Component
23 | public class CommitMsgQueue extends AbstractVoteMsgQueue {
24 | @Resource
25 | private PreMsgQueue preMsgQueue;
26 |
27 | private Logger logger = LoggerFactory.getLogger(getClass());
28 |
29 | @Override
30 | protected void deal(VoteMsg voteMsg, List voteMsgs) {
31 | String hash = voteMsg.getHash();
32 |
33 | //通过校验agree数量,来决定是否在本地生成Block
34 | long count = voteMsgs.stream().filter(VoteMsg::isAgree).count();
35 | logger.info("已经commit为true的数量为:"+ count);
36 | if (count >= pbftAgreeSize()) {
37 | Block block = preMsgQueue.findByHash(hash);
38 | if (block == null) {
39 | return;
40 | }
41 | //本地落地
42 | voteStateConcurrentHashMap.put(hash, true);
43 | ApplicationContextProvider.publishEvent(new AddBlockEvent(block));
44 | }
45 | }
46 |
47 | /**
48 | * 新区块生成后,clear掉map中number比区块小的所有数据
49 | */
50 | @Order(3)
51 | @EventListener(AddBlockEvent.class)
52 | public void blockGenerated(AddBlockEvent addBlockEvent) {
53 | Block block = (Block) addBlockEvent.getSource();
54 | clearOldBlockHash(block.getBlockHeader().getNumber());
55 | }
56 |
57 | }
58 |
--------------------------------------------------------------------------------
/block/src/main/java/com/magiccube/blockchain/socket/pbft/queue/MsgQueueManager.java:
--------------------------------------------------------------------------------
1 | package com.magiccube.blockchain.socket.pbft.queue;
2 |
3 | import com.magiccube.blockchain.ApplicationContextProvider;
4 | import com.magiccube.blockchain.socket.pbft.VoteType;
5 | import com.magiccube.blockchain.socket.pbft.msg.VoteMsg;
6 | import org.springframework.stereotype.Component;
7 |
8 |
9 | @Component
10 | public class MsgQueueManager {
11 |
12 | public void pushMsg(VoteMsg voteMsg) {
13 | BaseMsgQueue baseMsgQueue = null;
14 | switch (voteMsg.getVoteType()) {
15 | case VoteType
16 | .PREPREPARE:
17 | baseMsgQueue = ApplicationContextProvider.getBean(PreMsgQueue.class);
18 | break;
19 | case VoteType.PREPARE:
20 | baseMsgQueue = ApplicationContextProvider.getBean(PrepareMsgQueue.class);
21 | break;
22 | case VoteType.COMMIT:
23 | baseMsgQueue = ApplicationContextProvider.getBean(CommitMsgQueue.class);
24 | break;
25 | default:
26 | break;
27 | }
28 | if(baseMsgQueue != null) {
29 | baseMsgQueue.push(voteMsg);
30 | }
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/block/src/main/java/com/magiccube/blockchain/socket/pbft/queue/PreMsgQueue.java:
--------------------------------------------------------------------------------
1 | package com.magiccube.blockchain.socket.pbft.queue;
2 |
3 | import cn.hutool.core.bean.BeanUtil;
4 | import com.magiccube.blockchain.block.Block;
5 | import com.magiccube.blockchain.common.AppId;
6 | import com.magiccube.blockchain.common.timer.TimerManager;
7 | import com.magiccube.blockchain.core.event.AddBlockEvent;
8 | import com.magiccube.blockchain.core.sqlite.SqliteManager;
9 | import com.magiccube.blockchain.socket.pbft.VoteType;
10 | import com.magiccube.blockchain.socket.pbft.event.MsgPrepareEvent;
11 | import com.magiccube.blockchain.socket.pbft.msg.VoteMsg;
12 | import com.magiccube.blockchain.socket.pbft.msg.VotePreMsg;
13 | import org.slf4j.Logger;
14 | import org.slf4j.LoggerFactory;
15 | import org.springframework.context.ApplicationEventPublisher;
16 | import org.springframework.context.event.EventListener;
17 | import org.springframework.core.annotation.Order;
18 | import org.springframework.stereotype.Component;
19 |
20 | import javax.annotation.Resource;
21 | import java.util.concurrent.ConcurrentHashMap;
22 |
23 | /**
24 | * preprepare消息的存储,但凡收到请求生成Block的信息,都在这里处理
25 | */
26 | @Component
27 | public class PreMsgQueue extends BaseMsgQueue {
28 | @Resource
29 | private SqliteManager sqliteManager;
30 | @Resource
31 | private PrepareMsgQueue prepareMsgQueue;
32 | @Resource
33 | private ApplicationEventPublisher eventPublisher;
34 |
35 | private ConcurrentHashMap blockConcurrentHashMap = new ConcurrentHashMap<>();
36 |
37 | private Logger logger = LoggerFactory.getLogger(getClass());
38 |
39 | @Override
40 | protected void push(VoteMsg voteMsg) {
41 | //该队列里的是votePreMsg
42 | VotePreMsg votePreMsg = (VotePreMsg) voteMsg;
43 | String hash = votePreMsg.getHash();
44 | //避免收到重复消息
45 | if (blockConcurrentHashMap.get(hash) != null) {
46 | return;
47 | }
48 | //但凡是能进到该push方法的,都是通过基本校验的,但在并发情况下可能会相同number的block都进到投票队列中
49 | //需要对新进来的Vote信息的number进行校验,如果在比prepre阶段靠后的阶段中,已经出现了认证OK的同number的vote,则拒绝进入该队列
50 | if (prepareMsgQueue.otherConfirm(hash, voteMsg.getNumber())) {
51 | logger.info("拒绝进入Prepare阶段,hash为" + hash);
52 | return;
53 | }
54 | // 检测脚本是否正常
55 | try {
56 | sqliteManager.tryExecute(votePreMsg.getBlock());
57 | } catch (Exception e) {
58 | // 执行异常
59 | logger.info("sql指令预执行失败");
60 | return;
61 | }
62 |
63 | //存入Pre集合中
64 | blockConcurrentHashMap.put(hash, votePreMsg);
65 |
66 | //加入Prepare行列,推送给所有人
67 | VoteMsg prepareMsg = new VoteMsg();
68 | BeanUtil.copyProperties(voteMsg, prepareMsg);
69 | prepareMsg.setVoteType(VoteType.PREPARE);
70 | prepareMsg.setAppId(AppId.value);
71 | eventPublisher.publishEvent(new MsgPrepareEvent(prepareMsg));
72 | }
73 |
74 | /**
75 | * 根据hash,得到内存中的Block信息
76 | *
77 | * @param hash
78 | * hash
79 | * @return Block
80 | */
81 | public Block findByHash(String hash) {
82 | VotePreMsg votePreMsg = blockConcurrentHashMap.get(hash);
83 | if (votePreMsg != null) {
84 | return votePreMsg.getBlock();
85 | }
86 | return null;
87 | }
88 |
89 | /**
90 | * 新区块生成后,clear掉map中number比区块小的所有数据
91 | */
92 | @Order(3)
93 | @EventListener(AddBlockEvent.class)
94 | public void blockGenerated(AddBlockEvent addBlockEvent) {
95 | Block block = (Block) addBlockEvent.getSource();
96 | int number = block.getBlockHeader().getNumber();
97 | TimerManager.schedule(() -> {
98 | for (String key : blockConcurrentHashMap.keySet()) {
99 | if (blockConcurrentHashMap.get(key).getNumber() <= number) {
100 | blockConcurrentHashMap.remove(key);
101 | }
102 | }
103 | return null;
104 | }, 2000);
105 | }
106 | }
107 |
--------------------------------------------------------------------------------
/block/src/main/java/com/magiccube/blockchain/socket/pbft/queue/PrepareMsgQueue.java:
--------------------------------------------------------------------------------
1 | package com.magiccube.blockchain.socket.pbft.queue;
2 |
3 | import cn.hutool.core.bean.BeanUtil;
4 | import com.magiccube.blockchain.block.Block;
5 | import com.magiccube.blockchain.common.AppId;
6 | import com.magiccube.blockchain.core.event.AddBlockEvent;
7 | import com.magiccube.blockchain.socket.pbft.VoteType;
8 | import com.magiccube.blockchain.socket.pbft.event.MsgCommitEvent;
9 | import com.magiccube.blockchain.socket.pbft.msg.VoteMsg;
10 | import org.slf4j.Logger;
11 | import org.slf4j.LoggerFactory;
12 | import org.springframework.context.ApplicationEventPublisher;
13 | import org.springframework.context.event.EventListener;
14 | import org.springframework.core.annotation.Order;
15 | import org.springframework.stereotype.Component;
16 |
17 | import javax.annotation.Resource;
18 | import java.util.List;
19 |
20 | /**
21 | * Prepare阶段的消息队列
22 | */
23 | @Component
24 | public class PrepareMsgQueue extends AbstractVoteMsgQueue {
25 | @Resource
26 | private CommitMsgQueue commitMsgQueue;
27 | @Resource
28 | private ApplicationEventPublisher eventPublisher;
29 | private Logger logger = LoggerFactory.getLogger(getClass());
30 |
31 | /**
32 | * 收到节点(包括自己)针对某Block的Prepare消息
33 | *
34 | * @param voteMsg
35 | * voteMsg
36 | */
37 | @Override
38 | protected void deal(VoteMsg voteMsg, List voteMsgs) {
39 | String hash = voteMsg.getHash();
40 | VoteMsg commitMsg = new VoteMsg();
41 | BeanUtil.copyProperties(voteMsg, commitMsg);
42 | commitMsg.setVoteType(VoteType.COMMIT);
43 | commitMsg.setAppId(AppId.value);
44 | //开始校验并决定是否进入commit阶段
45 | //校验该vote是否合法
46 | if (commitMsgQueue.hasOtherConfirm(hash, voteMsg.getNumber())) {
47 | agree(commitMsg, false);
48 | } else {
49 | //开始校验拜占庭数量,如果agree的超过2f + 1,就commit
50 | long agreeCount = voteMsgs.stream().filter(VoteMsg::isAgree).count();
51 | long unAgreeCount = voteMsgs.size() - agreeCount;
52 |
53 | //开始发出commit的同意or拒绝的消息
54 | if (agreeCount >= pbftAgreeSize()) {
55 | agree(commitMsg, true);
56 | } else if (unAgreeCount >= pbftSize() + 1) {
57 | agree(commitMsg, false);
58 | }
59 | }
60 |
61 | }
62 |
63 | private void agree(VoteMsg commitMsg, boolean flag) {
64 | logger.info("Prepare阶段完毕,是否进入commit的标志是:" + flag);
65 | //发出拒绝commit的消息
66 | commitMsg.setAgree(flag);
67 | voteStateConcurrentHashMap.put(commitMsg.getHash(), flag);
68 | eventPublisher.publishEvent(new MsgCommitEvent(commitMsg));
69 | }
70 |
71 | /**
72 | * 判断大家是否已对其他的Block达成共识,如果true,则拒绝即将进入队列的Block
73 | *
74 | * @param hash
75 | * hash
76 | * @return 是否存在
77 | */
78 | public boolean otherConfirm(String hash, int number) {
79 | if (commitMsgQueue.hasOtherConfirm(hash, number)) {
80 | return true;
81 | }
82 | return hasOtherConfirm(hash, number);
83 | }
84 |
85 | /**
86 | * 新区块生成后,clear掉map中number比区块小的所有数据
87 | *
88 | * @param addBlockEvent addBlockEvent
89 | */
90 | @Order(3)
91 | @EventListener(AddBlockEvent.class)
92 | public void blockGenerated(AddBlockEvent addBlockEvent) {
93 | Block block = (Block) addBlockEvent.getSource();
94 | clearOldBlockHash(block.getBlockHeader().getNumber());
95 | }
96 | }
97 |
--------------------------------------------------------------------------------
/block/src/main/java/com/magiccube/blockchain/socket/server/BlockServerAioHandler.java:
--------------------------------------------------------------------------------
1 | package com.magiccube.blockchain.socket.server;
2 |
3 | import com.magiccube.blockchain.ApplicationContextProvider;
4 | import com.magiccube.blockchain.socket.distruptor.base.BaseEvent;
5 | import com.magiccube.blockchain.socket.distruptor.base.MessageProducer;
6 | import com.magiccube.blockchain.socket.base.AbstractAioHandler;
7 | import com.magiccube.blockchain.socket.packet.BlockPacket;
8 | import org.tio.core.ChannelContext;
9 | import org.tio.core.intf.Packet;
10 | import org.tio.server.intf.ServerAioHandler;
11 |
12 | /**
13 | * server端处理所有client请求的入口
14 | */
15 | public class BlockServerAioHandler extends AbstractAioHandler implements ServerAioHandler {
16 |
17 |
18 | /**
19 | * 自己是server,此处接收到客户端来的消息。这里是入口
20 | */
21 | @Override
22 | public void handler(Packet packet, ChannelContext channelContext) {
23 | BlockPacket blockPacket = (BlockPacket) packet;
24 |
25 | //使用Disruptor来publish消息。所有收到的消息都进入Disruptor,同BlockClientAioHandler
26 | ApplicationContextProvider.getBean(MessageProducer.class).publish(new BaseEvent(blockPacket, channelContext));
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/block/src/main/java/com/magiccube/blockchain/socket/server/BlockServerAioListener.java:
--------------------------------------------------------------------------------
1 | package com.magiccube.blockchain.socket.server;
2 |
3 | import org.slf4j.Logger;
4 | import org.slf4j.LoggerFactory;
5 | import org.tio.core.ChannelContext;
6 | import org.tio.core.intf.Packet;
7 | import org.tio.server.intf.ServerAioListener;
8 | import org.tio.utils.json.Json;
9 |
10 | /**
11 | * 连接状态的监听器
12 | */
13 | public class BlockServerAioListener implements ServerAioListener {
14 | private static Logger log = LoggerFactory.getLogger(BlockServerAioListener.class);
15 |
16 | @Override
17 | public void onAfterConnected(ChannelContext channelContext, boolean isConnected, boolean isReconnect) {
18 | log.info("onAfterConnected channelContext:{}, isConnected:{}, isReconnect:{}", channelContext, isConnected, isReconnect);
19 |
20 | //连接后,需要把连接会话对象设置给channelContext
21 | //channelContext.setAttribute(new ShowcaseSessionContext());
22 | }
23 |
24 | @Override
25 | public void onAfterDecoded(ChannelContext channelContext, Packet packet, int i) throws Exception {
26 |
27 | }
28 |
29 | @Override
30 | public void onAfterReceivedBytes(ChannelContext channelContext, int i) throws Exception {
31 | log.info("onAfterReceived channelContext:{}, packet:{}, packetSize:{}");
32 | }
33 |
34 |
35 | @Override
36 | public void onAfterSent(ChannelContext channelContext, Packet packet, boolean isSentSuccess) {
37 | log.info("onAfterSent channelContext:{}, packet:{}, isSentSuccess:{}", channelContext, Json.toJson(packet), isSentSuccess);
38 | }
39 |
40 | @Override
41 | public void onAfterHandled(ChannelContext channelContext, Packet packet, long l) throws Exception {
42 |
43 | }
44 |
45 | @Override
46 | public void onBeforeClose(ChannelContext channelContext, Throwable throwable, String remark, boolean isRemove) {
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/block/src/main/java/com/magiccube/blockchain/socket/server/BlockServerStarter.java:
--------------------------------------------------------------------------------
1 | package com.magiccube.blockchain.socket.server;
2 |
3 | import com.magiccube.blockchain.socket.common.Const;
4 | import org.springframework.stereotype.Component;
5 | import org.tio.server.AioServer;
6 | import org.tio.server.ServerGroupContext;
7 | import org.tio.server.intf.ServerAioHandler;
8 | import org.tio.server.intf.ServerAioListener;
9 |
10 | import javax.annotation.PostConstruct;
11 | import java.io.IOException;
12 |
13 | /**
14 | * server启动器
15 | */
16 | @Component
17 | public class BlockServerStarter {
18 |
19 | @PostConstruct
20 | public void serverStart() throws IOException {
21 | ServerAioHandler serverAioHandler = new BlockServerAioHandler();
22 | ServerAioListener serverAioListener = new BlockServerAioListener();
23 | ServerGroupContext serverGroupContext = new ServerGroupContext(serverAioHandler, serverAioListener);
24 | AioServer aioServer = new AioServer(serverGroupContext);
25 | //本机启动服务
26 | aioServer.start(null, Const.PORT);
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/block/src/main/resources/application.copy.yml:
--------------------------------------------------------------------------------
1 | spring:
2 | jpa:
3 | show-sql: false
4 | database-platform: com.magiccube.blockchain.core.sqlite.config.SQLiteDialect
5 | generate-ddl: true
6 | sqlite:
7 | dbName: a.db #本地sqlite的名字
8 | db:
9 | levelDB: false #在部分Windows机器上rocksDB会报错dll找不到,那么就用levelDB来替代
10 | rocksDB: true
11 | singleNode: true #如果是单节点测试,改成true
12 | version: 1
13 | name: ${NAME:maida}
14 | appId: ${APP_ID:wolf}
15 | managerUrl: ${MANAGER_URL:http://localhost:8888/}
16 | publicKey: A8WLqHTjcT/FQ2IWhIePNShUEcdCzu5dG+XrQU8OMu54
17 | privateKey: yScdp6fNgUU+cRUTygvJG4EBhDKmOMRrK4XJ9mKVQJ8=
18 | singeNode: true #单节点测试模式
--------------------------------------------------------------------------------
/block/src/main/resources/application.yml:
--------------------------------------------------------------------------------
1 | spring:
2 | jpa:
3 | show-sql: false
4 | database-platform: com.magiccube.blockchain.core.sqlite.config.SQLiteDialect
5 | generate-ddl: true
6 | sqlite:
7 | dbName: a.db #本地sqlite的名字
8 | db:
9 | levelDB: true
10 | rocksDB: false
11 | singleNode: true #如果是单节点测试,改成true
12 | version: 1
13 | name: ${NAME:single}
14 | appId: ${APP_ID:wolf}
15 | managerUrl: ${MANAGER_URL:http://localhost:8888/}
16 | publicKey: A8WLqHTjcT/FQ2IWhIePNShUEcdCzu5dG+XrQU8OMu54
17 | privateKey: yScdp6fNgUU+cRUTygvJG4EBhDKmOMRrK4XJ9mKVQJ8=
18 | singeNode: true #单节点测试模式
--------------------------------------------------------------------------------
/block/src/test/java/com/magiccube/blockchain/MagicCubeBlockchainApplicationTests.java:
--------------------------------------------------------------------------------
1 | package com.magiccube.blockchain;
2 |
3 | import org.junit.Test;
4 | import org.junit.runner.RunWith;
5 | import org.springframework.boot.test.context.SpringBootTest;
6 | import org.springframework.test.context.junit4.SpringRunner;
7 |
8 | @RunWith(SpringRunner.class)
9 | @SpringBootTest
10 | public class MagicCubeBlockchainApplicationTests {
11 |
12 | @Test
13 | public void contextLoads() {
14 | }
15 |
16 | }
17 |
--------------------------------------------------------------------------------
/magiccubevm.iml:
--------------------------------------------------------------------------------
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 |
--------------------------------------------------------------------------------
/manager/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | 4.0.0
5 |
6 | com.magiccube.blockmanager
7 | mc_blockchain_manager
8 | 0.0.1
9 | jar
10 |
11 | mc_blockchain_manager
12 | Demo project for Spring Boot
13 |
14 |
15 | org.springframework.boot
16 | spring-boot-starter-parent
17 | 2.0.0.RELEASE
18 |
19 |
20 |
21 |
22 | UTF-8
23 | UTF-8
24 | 1.8
25 |
26 |
27 |
28 |
29 | org.springframework.boot
30 | spring-boot-starter-data-jpa
31 |
32 |
33 | org.springframework.boot
34 | spring-boot-starter-web
35 |
36 |
37 |
38 | mysql
39 | mysql-connector-java
40 | runtime
41 |
42 |
43 | org.springframework.boot
44 | spring-boot-starter-test
45 | test
46 |
47 |
48 |
49 |
50 |
51 |
52 | org.springframework.boot
53 | spring-boot-maven-plugin
54 |
55 |
56 |
57 |
58 |
59 |
60 |
--------------------------------------------------------------------------------
/manager/src/main/java/com/magiccube/blockmanager/McBlockchainManagerApplication.java:
--------------------------------------------------------------------------------
1 | package com.magiccube.blockmanager;
2 |
3 | import org.springframework.boot.SpringApplication;
4 | import org.springframework.boot.autoconfigure.SpringBootApplication;
5 |
6 | @SpringBootApplication
7 | public class McBlockchainManagerApplication {
8 |
9 | public static void main(String[] args) {
10 | SpringApplication.run(McBlockchainManagerApplication.class, args);
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/manager/src/main/java/com/magiccube/blockmanager/bean/BaseData.java:
--------------------------------------------------------------------------------
1 | package com.magiccube.blockmanager.bean;
2 |
3 | public class BaseData {
4 | private int code;
5 | private String message;
6 |
7 | public int getCode() {
8 | return code;
9 | }
10 |
11 | public void setCode(int code) {
12 | this.code = code;
13 | }
14 |
15 | public String getMessage() {
16 | return message;
17 | }
18 |
19 | public void setMessage(String message) {
20 | this.message = message;
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/manager/src/main/java/com/magiccube/blockmanager/bean/MemberData.java:
--------------------------------------------------------------------------------
1 | package com.magiccube.blockmanager.bean;
2 |
3 | import com.magiccube.blockmanager.model.Member;
4 |
5 | import java.util.List;
6 |
7 | public class MemberData extends BaseData {
8 | private List members;
9 |
10 | public List getMembers() {
11 | return members;
12 | }
13 |
14 | public void setMembers(List members) {
15 | this.members = members;
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/manager/src/main/java/com/magiccube/blockmanager/bean/PermissionData.java:
--------------------------------------------------------------------------------
1 | package com.magiccube.blockmanager.bean;
2 |
3 | import com.magiccube.blockmanager.model.Permission;
4 |
5 | import java.util.List;
6 |
7 | public class PermissionData extends BaseData {
8 | private List permissions;
9 |
10 | public List getPermissions() {
11 | return permissions;
12 | }
13 |
14 | public void setPermissions(List permissions) {
15 | this.permissions = permissions;
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/manager/src/main/java/com/magiccube/blockmanager/constant/PermissionType.java:
--------------------------------------------------------------------------------
1 | package com.magiccube.blockmanager.constant;
2 |
3 | /**
4 | * 对表的权限
5 | */
6 | public interface PermissionType {
7 | /**
8 | * 表的创建者
9 | */
10 | byte OWNER = 1;
11 | /**
12 | * 所有权限
13 | */
14 | byte ALL = 2;
15 | byte ADD = 3;
16 | byte UPDATE = 4;
17 | byte DELETE = 5;
18 | /**
19 | * 不可见
20 | */
21 | byte NONE = -1;
22 | }
23 |
--------------------------------------------------------------------------------
/manager/src/main/java/com/magiccube/blockmanager/controller/MemberController.java:
--------------------------------------------------------------------------------
1 | package com.magiccube.blockmanager.controller;
2 |
3 | import com.magiccube.blockmanager.bean.MemberData;
4 | import com.magiccube.blockmanager.manager.MemberManager;
5 | import org.springframework.web.bind.annotation.GetMapping;
6 | import org.springframework.web.bind.annotation.RequestMapping;
7 | import org.springframework.web.bind.annotation.RestController;
8 |
9 | import javax.annotation.Resource;
10 | @RestController
11 | @RequestMapping("/member")
12 | public class MemberController {
13 | @Resource
14 | private MemberManager memberManager;
15 |
16 | // http://127.0.0.1:8888/member?name=single&appId=wolf&ip=192.168.1.75
17 | ///**
18 | // * 校验某服务是否合法,结果将决定对方能不能启动
19 | // * @param name 公司名
20 | // * @param appId 节点id
21 | // * @param ip 节点ip
22 | // * @return 合法与否的标志
23 | // {"code":0,"message":null,"members":[{"id":1,"createTime":"2018-03-19T06:37:26.000+0000","updateTime":"2018-03-19T06:37:28.000+0000","appId":"wolf","name":"single","ip":"192.168.1.75","groupId":"1"},{"id":2,"createTime":"2018-03-19T06:37:26.000+0000","updateTime":"2018-03-19T06:37:28.000+0000","appId":"mingyi","name":"mingyi","ip":"192.168.1.121","groupId":"1"}]}
24 | // */
25 | //@GetMapping
26 | //public Integer checkId(String name, String appId, String ip) {
27 | // return memberManager.checkIdAndIp(name, appId, ip);
28 | //}
29 |
30 | /**
31 | * 获取所有的节点信息
32 | * @param name name
33 | * @param appId appId
34 | * @param ip ip
35 | * @return ip
36 | */
37 | @GetMapping
38 | public MemberData member(String name, String appId, String ip) {
39 | return memberManager.memberData(name, appId, ip);
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/manager/src/main/java/com/magiccube/blockmanager/controller/PermissionController.java:
--------------------------------------------------------------------------------
1 | package com.magiccube.blockmanager.controller;
2 |
3 | import com.magiccube.blockmanager.bean.PermissionData;
4 | import com.magiccube.blockmanager.manager.PermissionManager;
5 | import org.springframework.web.bind.annotation.GetMapping;
6 | import org.springframework.web.bind.annotation.RequestMapping;
7 | import org.springframework.web.bind.annotation.RestController;
8 |
9 | import javax.annotation.Resource;
10 |
11 | @RestController
12 | @RequestMapping("permission")
13 | public class PermissionController {
14 | @Resource
15 | private PermissionManager permissionManager;
16 |
17 | /**
18 | * 查询某个联盟链的权限信息
19 | *
20 | * @param name
21 | * member的名字
22 | * @return 权限集合
23 | */
24 | @GetMapping
25 | public PermissionData findGroupPermission(String name) {
26 | return permissionManager.findGroupPermission(name);
27 | }
28 |
29 | /**
30 | * 添加权限信息,由表的owner来给其他member设置权限
31 | * @return 权限信息
32 | */
33 | //@PostMapping
34 | //public PermissionData addPermission(String publicKey, ) {
35 | //
36 | //}
37 | }
38 |
--------------------------------------------------------------------------------
/manager/src/main/java/com/magiccube/blockmanager/manager/MemberGroupManager.java:
--------------------------------------------------------------------------------
1 | package com.magiccube.blockmanager.manager;
2 |
3 | import com.magiccube.blockmanager.repository.MemberGroupRepository;
4 | import org.springframework.stereotype.Component;
5 |
6 | import javax.annotation.Resource;
7 |
8 |
9 | @Component
10 | public class MemberGroupManager {
11 | @Resource
12 | private MemberGroupRepository memberGroupRepository;
13 | }
14 |
--------------------------------------------------------------------------------
/manager/src/main/java/com/magiccube/blockmanager/manager/MemberManager.java:
--------------------------------------------------------------------------------
1 | package com.magiccube.blockmanager.manager;
2 |
3 | import com.magiccube.blockmanager.bean.MemberData;
4 | import com.magiccube.blockmanager.model.Member;
5 | import com.magiccube.blockmanager.repository.MemberRepository;
6 | import org.springframework.stereotype.Component;
7 |
8 | import javax.annotation.Resource;
9 | import java.util.List;
10 |
11 |
12 | @Component
13 | public class MemberManager {
14 | @Resource
15 | private MemberRepository memberRepository;
16 |
17 | /**
18 | * 查询某成员的groupId
19 | * @param memberName
20 | * 成员名
21 | * @return
22 | * 分组id
23 | */
24 | public String findGroupId(String memberName) {
25 | Member member = memberRepository.findFirstByName(memberName);
26 | if (member != null) {
27 | return member.getGroupId();
28 | }
29 | return null;
30 | }
31 |
32 | public MemberData memberData(String name, String appId, String ip) {
33 | MemberData memberData = new MemberData();
34 | Member member = memberRepository.findFirstByAppId(appId);
35 | //客户不存在
36 | if (member == null) {
37 | memberData.setCode(-1);
38 | memberData.setMessage("客户不存在");
39 | } else if (!member.getName().equals(name)) {
40 | //name错误
41 | memberData.setCode(-2);
42 | memberData.setMessage("name错误");
43 | } else if (!member.getIp().equals(ip)) {
44 | //ip错误
45 | memberData.setCode(-3);
46 | memberData.setMessage("ip错误");
47 | } else {
48 | memberData.setCode(0);
49 | String groupId = findGroupId(name);
50 | //如果该member是合法的,则返回给他联盟内所有的成员列表
51 | List members = memberRepository.findByGroupId(groupId);
52 | memberData.setMembers(members);
53 | }
54 | return memberData;
55 | }
56 |
57 | }
58 |
--------------------------------------------------------------------------------
/manager/src/main/java/com/magiccube/blockmanager/manager/PermissionManager.java:
--------------------------------------------------------------------------------
1 | package com.magiccube.blockmanager.manager;
2 |
3 | import com.magiccube.blockmanager.bean.PermissionData;
4 | import com.magiccube.blockmanager.model.Permission;
5 | import com.magiccube.blockmanager.repository.PermissionRepository;
6 | import org.springframework.stereotype.Service;
7 |
8 | import javax.annotation.Resource;
9 | import java.util.List;
10 |
11 | @Service
12 | public class PermissionManager {
13 | @Resource
14 | private PermissionRepository permissionRepository;
15 | @Resource
16 | private MemberManager memberManager;
17 |
18 | /**
19 | * 查询某个联盟内的所有权限
20 | *
21 | * @param memberName
22 | * memberName
23 | * @return PermissionData
24 | */
25 | public PermissionData findGroupPermission(String memberName) {
26 | PermissionData permissionData = new PermissionData();
27 | String groupId = memberManager.findGroupId(memberName);
28 | permissionData.setPermissions(findPermission(groupId));
29 | permissionData.setCode(0);
30 | return permissionData;
31 | }
32 |
33 | private List findPermission(String groupId) {
34 | return permissionRepository.findByGroupId(groupId);
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/manager/src/main/java/com/magiccube/blockmanager/model/Member.java:
--------------------------------------------------------------------------------
1 | package com.magiccube.blockmanager.model;
2 |
3 | import com.magiccube.blockmanager.model.base.BaseEntity;
4 |
5 | import javax.persistence.Entity;
6 | import javax.persistence.Table;
7 |
8 | /**
9 | * 联盟的成员
10 | */
11 | @Entity
12 | @Table(name = "member")
13 | public class Member extends BaseEntity {
14 | /**
15 | * 节点id,用于校验该客户是否合法,客户端启动时需要带着该值。一个公司可能有多个appId,相当于多个服务器节点
16 | */
17 | private String appId;
18 | /**
19 | * 成员名
20 | */
21 | private String name;
22 | /**
23 | * ip(可不设置,由该成员客户端启动后自行检测)
24 | */
25 | private String ip;
26 | /**
27 | * 属于哪个联盟链,groupId
28 | */
29 | private String groupId;
30 |
31 | @Override
32 | public String toString() {
33 | return "Member{" +
34 | "appId='" + appId + '\'' +
35 | ", name='" + name + '\'' +
36 | ", ip='" + ip + '\'' +
37 | ", groupId=" + groupId +
38 | '}';
39 | }
40 |
41 | public String getAppId() {
42 | return appId;
43 | }
44 |
45 | public void setAppId(String appId) {
46 | this.appId = appId;
47 | }
48 |
49 | public String getName() {
50 | return name;
51 | }
52 |
53 | public void setName(String name) {
54 | this.name = name;
55 | }
56 |
57 | public String getIp() {
58 | return ip;
59 | }
60 |
61 | public void setIp(String ip) {
62 | this.ip = ip;
63 | }
64 |
65 | public String getGroupId() {
66 | return groupId;
67 | }
68 |
69 | public void setGroupId(String groupId) {
70 | this.groupId = groupId;
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/manager/src/main/java/com/magiccube/blockmanager/model/MemberGroup.java:
--------------------------------------------------------------------------------
1 | package com.magiccube.blockmanager.model;
2 |
3 | import com.magiccube.blockmanager.model.base.BaseEntity;
4 |
5 | import javax.persistence.Entity;
6 | import javax.persistence.Table;
7 |
8 | /**
9 | * 联盟链,多个节点组成一个group,一个group为一个联盟链
10 | */
11 | @Entity
12 | @Table(name = "member_group")
13 | public class MemberGroup extends BaseEntity {
14 | private String name;
15 | /**
16 | * 设置一个业务id
17 | */
18 | private String groupId;
19 |
20 | public String getName() {
21 | return name;
22 | }
23 |
24 | public void setName(String name) {
25 | this.name = name;
26 | }
27 |
28 | public String getGroupId() {
29 | return groupId;
30 | }
31 |
32 | public void setGroupId(String groupId) {
33 | this.groupId = groupId;
34 | }
35 |
36 | @Override
37 | public String toString() {
38 | return "Group{" +
39 | "name='" + name + '\'' +
40 | ", groupId='" + groupId + '\'' +
41 | '}';
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/manager/src/main/java/com/magiccube/blockmanager/model/Permission.java:
--------------------------------------------------------------------------------
1 | package com.magiccube.blockmanager.model;
2 |
3 | import com.magiccube.blockmanager.model.base.BaseEntity;
4 |
5 | import javax.persistence.Entity;
6 | import javax.persistence.Table;
7 |
8 | /**
9 | * 权限,主要存储各member对表的权限信息,如不可见、只能ADD,可以UPDATE、DELETE等等组合
10 | */
11 | @Entity
12 | @Table(name = "permission")
13 | public class Permission extends BaseEntity {
14 | /**
15 | * 哪张表
16 | */
17 | private String tableName;
18 | /**
19 | * 操作权限,见PermissionType类
20 | */
21 | private byte permissionType;
22 | /**
23 | * 公钥(账户的概念,能具体到某个member,为*则代表所有节点,不具体指定某个)
24 | */
25 | private String publicKey;
26 | /**
27 | * 该权限是归属于哪个group的。节点只需要获取自己group的权限信息,不需要知道别的group的
28 | */
29 | private String groupId;
30 |
31 | @Override
32 | public String toString() {
33 | return "Permission{" +
34 | "tableName='" + tableName + '\'' +
35 | ", permissionType=" + permissionType +
36 | ", publicKey='" + publicKey + '\'' +
37 | ", groupId='" + groupId + '\'' +
38 | '}';
39 | }
40 |
41 | public String getPublicKey() {
42 | return publicKey;
43 | }
44 |
45 | public void setPublicKey(String publicKey) {
46 | this.publicKey = publicKey;
47 | }
48 |
49 | public String getGroupId() {
50 | return groupId;
51 | }
52 |
53 | public void setGroupId(String groupId) {
54 | this.groupId = groupId;
55 | }
56 |
57 | public String getTableName() {
58 | return tableName;
59 | }
60 |
61 | public void setTableName(String tableName) {
62 | this.tableName = tableName;
63 | }
64 |
65 | public byte getPermissionType() {
66 | return permissionType;
67 | }
68 |
69 | public void setPermissionType(byte permissionType) {
70 | this.permissionType = permissionType;
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/manager/src/main/java/com/magiccube/blockmanager/model/base/BaseEntity.java:
--------------------------------------------------------------------------------
1 | package com.magiccube.blockmanager.model.base;
2 |
3 | import javax.persistence.GeneratedValue;
4 | import javax.persistence.GenerationType;
5 | import javax.persistence.Id;
6 | import javax.persistence.MappedSuperclass;
7 | import java.util.Date;
8 |
9 | @MappedSuperclass
10 | public class BaseEntity {
11 | @Id
12 | @GeneratedValue(strategy = GenerationType.IDENTITY)
13 | private Long id;
14 |
15 | private Date createTime;
16 |
17 | private Date updateTime;
18 |
19 | public Date getCreateTime() {
20 | return createTime;
21 | }
22 |
23 | public void setCreateTime(Date createTime) {
24 | this.createTime = createTime;
25 | }
26 |
27 | public Date getUpdateTime() {
28 | return updateTime;
29 | }
30 |
31 | public void setUpdateTime(Date updateTime) {
32 | this.updateTime = updateTime;
33 | }
34 |
35 | public Long getId() {
36 | return id;
37 | }
38 |
39 | public void setId(Long id) {
40 | this.id = id;
41 | }
42 |
43 | @Override
44 | public String toString() {
45 | return "BaseEntity{" +
46 | "id=" + id +
47 | ", createTime=" + createTime +
48 | ", updateTime=" + updateTime +
49 | '}';
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/manager/src/main/java/com/magiccube/blockmanager/repository/MemberGroupRepository.java:
--------------------------------------------------------------------------------
1 | package com.magiccube.blockmanager.repository;
2 |
3 | import com.magiccube.blockmanager.model.MemberGroup;
4 | import org.springframework.data.jpa.repository.JpaRepository;
5 |
6 |
7 | public interface MemberGroupRepository extends JpaRepository {
8 | }
9 |
--------------------------------------------------------------------------------
/manager/src/main/java/com/magiccube/blockmanager/repository/MemberRepository.java:
--------------------------------------------------------------------------------
1 | package com.magiccube.blockmanager.repository;
2 |
3 | import com.magiccube.blockmanager.model.Member;
4 | import org.springframework.data.jpa.repository.JpaRepository;
5 |
6 | import java.util.List;
7 |
8 |
9 | public interface MemberRepository extends JpaRepository {
10 | List findByName(String name);
11 |
12 | /**
13 | * 查询同一个联盟内,除自己外其他的所有节点
14 | *
15 | * @param groupId
16 | * groupId
17 | * @param id
18 | * 自己节点id
19 | * @return 成员集合
20 | */
21 | List findByGroupIdAndAppIdNot(String groupId, String id);
22 |
23 | /**
24 | * 查询某个节点
25 | *
26 | * @param appId
27 | * appId
28 | * @return Member
29 | */
30 | Member findFirstByAppId(String appId);
31 |
32 | /**
33 | * 查询一个联盟内所有节点
34 | *
35 | * @param groupId
36 | * groupId
37 | * @return 成员集合
38 | */
39 | List findByGroupId(String groupId);
40 |
41 | /**
42 | * 根据机构名查询
43 | *
44 | * @param name
45 | * name
46 | * @return Member
47 | */
48 | Member findFirstByName(String name);
49 | }
50 |
--------------------------------------------------------------------------------
/manager/src/main/java/com/magiccube/blockmanager/repository/PermissionRepository.java:
--------------------------------------------------------------------------------
1 | package com.magiccube.blockmanager.repository;
2 |
3 | import com.magiccube.blockmanager.model.Permission;
4 | import org.springframework.data.jpa.repository.JpaRepository;
5 |
6 | import java.util.List;
7 |
8 |
9 | public interface PermissionRepository extends JpaRepository {
10 | /**
11 | * 查询某个group的所有权限
12 | * @param groupId
13 | * 联盟链id
14 | * @return
15 | * 权限集合
16 | */
17 | List findByGroupId(String groupId);
18 |
19 | }
20 |
--------------------------------------------------------------------------------
/manager/src/main/resources/application-local.yml:
--------------------------------------------------------------------------------
1 | spring:
2 | datasource:
3 | driver-class-name: com.mysql.jdbc.Driver
4 | url: jdbc:mysql://localhost:3306/blockchain_manager?autoReconnect=true&useUnicode=true
5 | username: root
6 | password: 123456
--------------------------------------------------------------------------------
/manager/src/main/resources/application-prod.yml:
--------------------------------------------------------------------------------
1 | spring:
2 | datasource:
3 | driver-class-name: com.mysql.jdbc.Driver
4 | url: jdbc:mysql://${MYSQL_URL}/blockchain_manager?autoReconnect=true&useUnicode=true
5 | username: md
6 | password: ${MYSQL_PASS}
7 | server:
8 | port: 8080
--------------------------------------------------------------------------------
/manager/src/main/resources/application.yml:
--------------------------------------------------------------------------------
1 | spring:
2 | jpa:
3 | database: mysql
4 | show-sql: true
5 | hibernate:
6 | ddl-auto: update
7 | naming:
8 | physical-strategy: org.springframework.boot.orm.jpa.hibernate.SpringPhysicalNamingStrategy
9 | database-platform: org.hibernate.dialect.MySQL5InnoDBDialect #不加这句则默认为myisam引擎
10 | profiles:
11 | active: ${ENV:local}
12 | logging:
13 | file: ./logback.log
14 | server:
15 | port: 8888
--------------------------------------------------------------------------------
/manager/src/test/java/com/magiccube/blockmanager/McBlockchainManagerApplicationTests.java:
--------------------------------------------------------------------------------
1 | package com.magiccube.blockmanager;
2 |
3 | import org.junit.Test;
4 | import org.junit.runner.RunWith;
5 | import org.springframework.boot.test.context.SpringBootTest;
6 | import org.springframework.test.context.junit4.SpringRunner;
7 |
8 | @RunWith(SpringRunner.class)
9 | @SpringBootTest
10 | public class McBlockchainManagerApplicationTests {
11 |
12 | @Test
13 | public void contextLoads() {
14 | }
15 |
16 | }
17 |
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 4.0.0
4 | com.magiccube
5 | blockchain
6 | 0.0.1
7 | blockchain
8 | magiccube blockchain
9 |
10 |
11 | 1.8
12 |
13 |
14 |
15 | block
16 | manager
17 |
18 |
19 |
--------------------------------------------------------------------------------