├── .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 | --------------------------------------------------------------------------------