Blockchain Implementation With Java Code

Let's take a look at a possible blockchain implementation using Java. We build up from first principles and develop some code to help show how it all fits together.

  · Java Zone · Tutorial
 

Bitcoin is hot — and what an understatement that is. While the future of cryptocurrency is somewhat uncertain, blockchain — the technology used to drive Bitcoin — is also very popular.

Blockchain has an almost endless application scope. It also arguably has the potential to disrupt enterprise automation. There is a lot of information available covering what and how blockchain works. We have a free whitepaper that goes into blockchain technology (no registration required).

This article will focus on the blockchain architecture; particularly, demonstrating how the "immutable, append-only" distributed ledger works with simplistic code examples.

As developers, seeing things in code can be much more useful in understanding how it works when compared to simply reading technical articles. At least that's the case for me. So, let's get started!

Blockchain in a Nutshell

Let's first give a quick summary of blockchain. A block contains some header information and a set or block of transactions of any type of data. The chain starts with a first (Genesis) block. As transactions are added/appended, new blocks are created based on how many transactions can be stored within a block.

When a block threshold size is exceeded, then a new block of transactions is created. The new block is linked to the previous block, hence the term blockchain.

Immutability

Blockchains are immutable because an SHA-256 hash is computed for transactions. A block's contents are also hashed which provide a unique identifier. Moreover, the hash from the linked, previous block is also stored and hashed in the block header.

This is why trying to tamper with a blockchain block is basically impossible, at least with current computing power. Here's a partial Java class definition showing the properties of the block.

 
...
 
public class Block<T extends Tx> {
 
public long timeStamp;
 
private int index;
 
private List<T> transactions = new ArrayList<T>();
 
private String hash;
 
private String previousHash;
 
private String merkleRoot;
 
private String nonce = "0000";
 
 
 
// caches Transaction SHA256 hashes
 
    public Map<String,T> map = new HashMap<String,T>();
 
...
 

Notice the injected generic type is of type Tx. This allows transaction data to vary. Also, the previousHashproperty will reference the previous block's hash. The merkleRoot and nonce properties will be described in a bit.

Block Hash

Each block can compute a block hash. This is essentially a hash of all the block's properties concatenated together, including the previous block's hash and a SHA-256 hash computed from that.

Here is the method defined in the Block.java class that computes the hash.

 
...
 
public void computeHash() {
 
     Gson parser = new Gson(); // probably should cache this instance
 
     String serializedData = parser.toJson(transactions);  
 
     setHash(SHA256.generateHash(timeStamp + index + merkleRoot + serializedData + nonce + previousHash));
 
     }
 
...
 

The block transactions are serialized to a JSON string so it can be appended to the block properties before hashing.

The Chain

The blockchain manages blocks by accepting transactions. When a predetermined threshold has been reached, then a block is created. Here is a SimpleBlockChain.java partial implementation:

 
...
 
...
 
public class SimpleBlockchain<T extends Tx> {
 
public static final int BLOCK_SIZE = 10;
 
public List<Block<T>> chain = new ArrayList<Block<T>>();
 
 
 
public SimpleBlockchain() {
 
// create genesis block
 
chain.add(newBlock());
 
}
 
 
 
...
 

Notice that the chain property holds a list of Blocks typed with a Tx type. Also, the no arg constructor creates an initial "genesis" block when the chain is created. Here is the source for the newBlock() method.

 
...
 
public Block<T> newBlock() {
 
int count = chain.size();
 
String previousHash = "root";
 
 
 
if (count > 0)
 
previousHash = blockChainHash();
 
 
 
Block<T> block = new Block<T>();
 
 
 
block.setTimeStamp(System.currentTimeMillis());
 
block.setIndex(count);
 
block.setPreviousHash(previousHash);
 
return block;
 
}
 
...
 

This new block method will create a new block instance, seed appropriate values, and assign the previous block's hash (which will be the hash of the head of the chain). It will then return the block.

Blocks can be validated before being added to the chain by comparing the new block's previous hash to the last block (head) of the chain to make sure they match. Here's a SimpleBlockchain.java method depicting this.

 
....
 
public void addAndValidateBlock(Block<T> block) {
 
 
 
// compare previous block hash, add if valid
 
Block<T> current = block;
 
for (int i = chain.size() - 1; i >= 0; i--) {
 
Block<T> b = chain.get(i);
 
if (b.getHash().equals(current.getPreviousHash())) {
 
current = b;
 
} else {
 
 
 
throw new RuntimeException("Block Invalid");
 
}
 
 
 
}
 
 
 
this.chain.add(block);
 
}
 
...
 

The entire blockchain is validated by the looping-over of the chain to ensure a block's hash still matches the previous block's hash.

Here is the SimpleBlockChain.java validate() method implementation.

 
...
 
public boolean validate() {
 
 
 
String previousHash = null;
 
for (Block<T> block : chain) {
 
String currentHash = block.getHash();
 
if (!currentHash.equals(previousHash)) {
 
return false;
 
}
 
 
 
previousHash = currentHash;
 
 
 
}
 
 
 
return true;
 
 
 
}
 
...
 

You can see that trying to fudge transaction data or any other property in any way is very difficult. And, as the chain grows, it continues to get very, very, very difficult, essentially impossible — that is, until quantum computers are available!

Adding Transactions

Another significant technical point of blockchain technology is that it is distributed. The fact that they are append-only helps in duplicating the blockchain across nodes participating in the blockchain network. Nodes typically communicate in a peer-to-peer fashion, as is the case with Bitcoin, but it does not have to be this way. Other blockchain implementations use a decentralized approach, like using APIs via HTTP. However, that is a topic for another article.

Transactions can represent just about anything. A transaction could contain code to execute (i.e Smart Contract) or store and append information about some kind of business transaction.

Smart contract: Computer protocol intended to digitally facilitate, verify, or enforce the negotiation or performance of a contract.

In the case of Bitcoin, a transaction contains an amount from an owner's account and amount(s) to other accounts (e.g. transferring Bitcoin amounts between accounts). The transaction also includes public keys and account IDs within it, so transferring is done securely. But that's Bitcoin-specific.

Transactions are added to a network and pooled; they are not in a block or the chain itself.

This is where a blockchain consensus mechanism comes into play. There are a number of proven consensus algorithm and patterns beyond the scope of this article.

경축! 아무것도 안하여 에스천사게임즈가 새로운 모습으로 재오픈 하였습니다.
어린이용이며, 설치가 필요없는 브라우저 게임입니다.
https://s1004games.com

Mining is a consensus mechanism that Bitcoin blockchains use. That is the type of consensus discussed further down this article. The consensus mechanism gathers transactions, builds a block with them, and then adds the block to the chain. The chain then validates the new block of transactions before adding to the chain.

Merkle Trees

Transactions are hashed and added to the block. A Merkle Tree data structure is created to compute a Merkle Root hash. Each block will store the root of the Merkle tree, which is a balanced binary tree of hashes where interior nodes are hashes of the two child hashes, all the way up to the root hash, which is the Merkle Root.

This tree is used to validate the block transactions. If a single bit of information is changed in any transaction, the Merkle Root will be invalid. Also, they can help with transmitting blocks in a distributed fashion, since the structure allows only a single branch of transaction hashes required to add and validate the entire block of transactions.

Here's the method in the Block.java class that creates a Merkle Tree out of the transaction list.

 
...
 
public List<String> merkleTree() {
 
ArrayList<String> tree = new ArrayList<>();
 
// Start by adding all the hashes of the transactions as leaves of the
 
// tree.
 
for (T t : transactions) {
 
tree.add(t.hash());
 
}
 
int levelOffset = 0; // Offset in the list where the currently processed
 
// level starts.
 
// Step through each level, stopping when we reach the root (levelSize
 
// == 1).
 
for (int levelSize = transactions.size(); levelSize > 1; levelSize = (levelSize + 1) / 2) {
 
// For each pair of nodes on that level:
 
for (int left = 0; left < levelSize; left += 2) {
 
// The right hand node can be the same as the left hand, in the
 
// case where we don't have enough
 
// transactions.
 
int right = Math.min(left + 1, levelSize - 1);
 
String tleft = tree.get(levelOffset + left);
 
String tright = tree.get(levelOffset + right);
 
tree.add(SHA256.generateHash(tleft + tright));
 
}
 
// Move to the next level.
 
levelOffset += levelSize;
 
}
 
return tree;
 
}
 
 
 
...
 

This method is used to compute a Merkle Tree root for the block. The companion project has a Merkle Tree unit test that attempts to add a transaction to a block and verify that the Merkle Roots have changed. Here is the source code for the unit test.

 
...
 
@Test
 
public void merkleTreeTest() {
 
 
 
// create chain, add transaction
 
 
 
SimpleBlockchain<Transaction> chain1 = new SimpleBlockchain<Transaction>();
 
 
 
chain1.add(new Transaction("A")).add(new Transaction("B")).add(new Transaction("C")).add(new Transaction("D"));
 
 
 
// get a block in chain
 
Block<Transaction> block = chain1.getHead();
 
 
 
System.out.println("Merkle Hash tree :" + block.merkleTree());
 
 
 
// get a transaction from block
 
Transaction tx = block.getTransactions().get(0);
 
 
 
// see if block transactions are valid, they should be
 
block.transasctionsValid();
 
assertTrue(block.transasctionsValid());
 
 
 
// mutate the data of a transaction
 
tx.setValue("Z");
 
 
 
// block should no longer be valid, blocks MerkleRoot does not match computed merkle tree of transactions
 
assertFalse(block.transasctionsValid());
 
 
 
}
 
 
 
...
 

This unit test emulates validating transactions, then changing a transaction in a block outside of the consensus mechanism, e.g. if someone tries to change transaction data.

Remember, blockchains are append-only, and as the blockchain data structure is shared between nodes, block data structure (including the Merkle Root) are hashed and connected to other blocks. All nodes can validate new blocks and existing blocks can be easily proved as valid. So, a miner trying to add a bogus block or a node attempting to adjust older transactions are effectively not possible before the sun grows to a supernova and gives all a really nice tan.

Mining Proof of Work

The process of combining transactions in into a block, then submitting it for validation by members of the chain, is referred to as "mining" in the Bitcoin world.

More generally, in blockchain speak, this is called consensus. There are different types of proven distributed consensus algorithms. Which mechanism to use is based upon whether you have a public or permissioned blockchain. Our white paper describes this more in depth, but this article is focusing on the blockchain mechanics, so this example we will apply a proof-of-work consensus mechanism.

So, mining nodes will listen for transactions being executed by the blockchain and will perform a simple mathematical puzzle. This puzzle produces block hash with a predetermined set of leading zeros using a nonce value that is changed on every iteration until the leading zero hash is found.

The example Java project has a Miner.java class with a proofOfWork(Block block) method implementation, as shown below.

 
private String proofOfWork(Block block) {
 
 
 
String nonceKey = block.getNonce();
 
long nonce = 0;
 
boolean nonceFound = false;
 
String nonceHash = "";
 
 
 
Gson parser = new Gson();
 
String serializedData = parser.toJson(transactionPool);
 
String message = block.getTimeStamp() + block.getIndex() + block.getMerkleRoot() + serializedData
 
+ block.getPreviousHash();
 
 
 
while (!nonceFound) {
 
 
 
nonceHash = SHA256.generateHash(message + nonce);
 
nonceFound = nonceHash.substring(0, nonceKey.length()).equals(nonceKey);
 
nonce++;
 
 
 
}
 
 
 
return nonceHash;
 
 
 
}
 

Again, this is simplified, but the miner implementation will perform a proof-of-work hash for the block once a certain number of transactions have been received. The algorithm simply loops and creates an SHA-256 hash of the block until the leading number hash is produced.

This can take a lot of time, which is why specific GPU microprocessors have been implemented to perform and solve this problem as fast as possible.

Unit Tests

You can see all these concepts pulled together with the Java example project's JUnit tests available on GitHub.

Give this a run. It will let you check out how this simple blockchain works.

Also, if you are a C#'er reading, this (we won't tell anyone), we also have these same examples written in C#. Here is the link to the example C# blockchain implementation.

Final Thoughts

Hopefully, this post has provided you enough interest and insight to keep researching blockchain technology.

All of the examples introduced in this article are used in our in-depth blockchain white paper (no registration required to read). These same examples are in more detail in the white paper.

Also, if you want to see a full blockchain implementation in Java, here's a link to the open-source BitcoinJ project. You'll see these concepts in action in a real production implementation.

If so, next recommended learning steps are to check out a more production-based open-source blockchain framework. A good example is HyperLedger Fabric. That will be the subject of my next article — stay tuned!

 

 
[출처] https://dzone.com/articles/blockchain-implementation-with-java-code

 

 

 

본 웹사이트는 광고를 포함하고 있습니다.
광고 클릭에서 발생하는 수익금은 모두 웹사이트 서버의 유지 및 관리, 그리고 기술 콘텐츠 향상을 위해 쓰여집니다.
번호 제목 글쓴이 날짜 조회 수
35 [EMF] EMF Tutorial EMF 튜터리얼 file 졸리운_곰 2023.08.23 283
34 Eclipse RAP Tutorial for Beginners - Workbench Application (OLD) file 졸리운_곰 2021.01.30 323
33 Learn Eclipse GMF in 15 minutes file 졸리운_곰 2019.11.27 253
32 [Eclipse] GEF entry series (10, an implementation of the form) file 졸리운_곰 2019.11.25 212
31 GEF Programmer Guide 번역 졸리운_곰 2019.11.25 227
30 Learn Eclipse GMF in 15 minutes file 졸리운_곰 2019.11.20 224
29 RCP 에디터 정리 졸리운_곰 2019.11.20 333
28 다른 그림과 관련하여 GEF 편집기 레이아웃에서 그림의 위치 제한 조건을 동적으로 계산 Dynamically calculating the position constraints for a figure in a GEF editor layout in relation to another figure file 졸리운_곰 2019.11.20 277
27 RCP 등에서 .mf 파일로 다른 프로젝트 익스포트 포함시 라이브러리(메소드)를 찾지 못할 때, Eclipse RCP - cant resolve importing libraries in final build file 졸리운_곰 2019.10.15 410
26 ESE2006-EclipseModelingSymposium15_GMF.pdf file 졸리운_곰 2019.09.21 302
25 GMF_Creation_Review.pdf file 졸리운_곰 2019.09.21 366
24 Eclipse EMF and GMF Tutorial file 졸리운_곰 2019.09.21 222
23 GMF Tutorial/ko file 졸리운_곰 2019.09.20 347
22 Model Driven Architecture approach to domain of graphical editors file 졸리운_곰 2019.09.20 268
21 Single_Sourcing_RAP_RCP_en.pdf file 졸리운_곰 2019.05.15 311
20 Rich client platform 설명 및 배우기 참고 졸리운_곰 2019.05.15 309
19 Rich Ajax Platform, Part 1: 소개 file 졸리운_곰 2019.05.15 320
18 또 하나의 크로스 플랫폼: Eclipse RAP file 졸리운_곰 2019.05.15 319
17 Eclipse 4 RCP 튜토리얼(완료) file 졸리운_곰 2019.05.14 977
16 Updating UI in Eclipse RCP 졸리운_곰 2015.11.07 408
대표 김성준 주소 : 경기 용인 분당수지 U타워 등록번호 : 142-07-27414
통신판매업 신고 : 제2012-용인수지-0185호 출판업 신고 : 수지구청 제 123호 개인정보보호최고책임자 : 김성준 sjkim70@stechstar.com
대표전화 : 010-4589-2193 [fax] 02-6280-1294 COPYRIGHT(C) stechstar.com ALL RIGHTS RESERVED