Merge pull request #17 from nicksavers/master
Block stateRoot generation & Initial usage of LevelDB (which still needs work)
This commit is contained in:
commit
f74841ac74
|
@ -92,6 +92,11 @@ public class SystemProperties {
|
||||||
return Integer.parseInt(prop.getProperty("peer.discovery.port"));
|
return Integer.parseInt(prop.getProperty("peer.discovery.port"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean databaseReset(){
|
||||||
|
if(prop.isEmpty()) return false;
|
||||||
|
return Boolean.parseBoolean(prop.getProperty("database.reset"));
|
||||||
|
}
|
||||||
|
|
||||||
public String activePeerIP(){
|
public String activePeerIP(){
|
||||||
if(prop.isEmpty()) return "54.201.28.117";
|
if(prop.isEmpty()) return "54.201.28.117";
|
||||||
return prop.getProperty("peer.active.ip");
|
return prop.getProperty("peer.active.ip");
|
||||||
|
@ -107,7 +112,6 @@ public class SystemProperties {
|
||||||
return prop.getProperty("samples.dir");
|
return prop.getProperty("samples.dir");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public String toString() {
|
public String toString() {
|
||||||
Enumeration<?> e = prop.propertyNames();
|
Enumeration<?> e = prop.propertyNames();
|
||||||
while (e.hasMoreElements()) {
|
while (e.hasMoreElements()) {
|
||||||
|
|
|
@ -0,0 +1,92 @@
|
||||||
|
package org.ethereum.core;
|
||||||
|
|
||||||
|
import org.ethereum.crypto.ECKey;
|
||||||
|
import org.ethereum.crypto.HashUtil;
|
||||||
|
import org.ethereum.util.RLP;
|
||||||
|
import org.ethereum.util.Utils;
|
||||||
|
|
||||||
|
import java.math.BigInteger;
|
||||||
|
|
||||||
|
public class AccountState {
|
||||||
|
|
||||||
|
private ECKey ecKey;
|
||||||
|
private byte[] rlpEncoded;
|
||||||
|
|
||||||
|
/* A value equal to the number of transactions sent
|
||||||
|
* from this address, or, in the case of contract accounts,
|
||||||
|
* the number of contract-creations made by this account */
|
||||||
|
private BigInteger nonce;
|
||||||
|
|
||||||
|
/* A scalar value equal to the number of Wei owned by this address */
|
||||||
|
private BigInteger balance;
|
||||||
|
|
||||||
|
/* A 256-bit hash of the root node of a trie structure
|
||||||
|
* that encodes the storage contents of the contract,
|
||||||
|
* itself a simple mapping between byte arrays of size 32.
|
||||||
|
* The hash is formally denoted σ[a] s .
|
||||||
|
*
|
||||||
|
* Since I typically wish to refer not to the trie’s root hash
|
||||||
|
* but to the underlying set of key/value pairs stored within,
|
||||||
|
* I define a convenient equi valence TRIE (σ[a] s ) ≡ σ[a] s .
|
||||||
|
* It shall be understood that σ[a] s is not a ‘physical’ member
|
||||||
|
* of the account and does not contribute to its later serialisation */
|
||||||
|
private byte[] stateRoot = new byte[0];
|
||||||
|
|
||||||
|
/* The hash of the EVM code of this contract—this is the code
|
||||||
|
* that gets executed should this address receive a message call;
|
||||||
|
* it is immutable and thus, unlike all other fields, cannot be changed
|
||||||
|
* after construction. All such code fragments are contained in
|
||||||
|
* the state database under their corresponding hashes for later
|
||||||
|
* retrieval */
|
||||||
|
private byte[] codeHash = HashUtil.sha3(new byte[0]);
|
||||||
|
|
||||||
|
public AccountState() {
|
||||||
|
this(new ECKey(Utils.getRandom()));
|
||||||
|
}
|
||||||
|
|
||||||
|
public AccountState(ECKey ecKey) {
|
||||||
|
this(ecKey, BigInteger.ZERO, BigInteger.ZERO);
|
||||||
|
}
|
||||||
|
|
||||||
|
public AccountState(ECKey ecKey, BigInteger nonce, BigInteger balance) {
|
||||||
|
this.ecKey = ecKey;
|
||||||
|
this.nonce = nonce;
|
||||||
|
this.balance = balance;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AccountState(BigInteger nonce, BigInteger balance) {
|
||||||
|
this.nonce = nonce;
|
||||||
|
this.balance = balance;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ECKey getEcKey() {
|
||||||
|
return ecKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BigInteger getNonce() {
|
||||||
|
return nonce;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void incrementNonce(){
|
||||||
|
this.nonce = nonce.add(BigInteger.ONE);
|
||||||
|
}
|
||||||
|
|
||||||
|
public BigInteger getBalance() {
|
||||||
|
return balance;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addToBalance(BigInteger value){
|
||||||
|
this.balance = balance.add(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] getEncoded() {
|
||||||
|
if(rlpEncoded == null) {
|
||||||
|
byte[] nonce = RLP.encodeBigInteger(this.nonce);
|
||||||
|
byte[] balance = RLP.encodeBigInteger(this.balance);
|
||||||
|
byte[] stateRoot = RLP.encodeElement(this.stateRoot);
|
||||||
|
byte[] codeHash = RLP.encodeElement(this.codeHash);
|
||||||
|
this.rlpEncoded = RLP.encodeList(balance, nonce, stateRoot, codeHash);
|
||||||
|
}
|
||||||
|
return rlpEncoded;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,55 +0,0 @@
|
||||||
package org.ethereum.core;
|
|
||||||
|
|
||||||
import org.ethereum.crypto.ECKey;
|
|
||||||
import org.ethereum.util.Utils;
|
|
||||||
|
|
||||||
import java.math.BigInteger;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* www.ethereumJ.com
|
|
||||||
* User: Roman Mandeleil
|
|
||||||
* Created on: 21/05/2014 10:43
|
|
||||||
*/
|
|
||||||
public class AddressState {
|
|
||||||
|
|
||||||
private ECKey ecKey;
|
|
||||||
private BigInteger nonce;
|
|
||||||
private BigInteger balance;
|
|
||||||
|
|
||||||
public AddressState() {
|
|
||||||
ecKey = new ECKey(Utils.getRandom());
|
|
||||||
nonce = BigInteger.ZERO;
|
|
||||||
balance = BigInteger.ZERO;
|
|
||||||
}
|
|
||||||
|
|
||||||
public AddressState(ECKey ecKey) {
|
|
||||||
this();
|
|
||||||
this.ecKey = ecKey;
|
|
||||||
}
|
|
||||||
|
|
||||||
public AddressState(ECKey ecKey, BigInteger nonce, BigInteger balance) {
|
|
||||||
this.ecKey = ecKey;
|
|
||||||
this.nonce = nonce;
|
|
||||||
this.balance = balance;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ECKey getEcKey() {
|
|
||||||
return ecKey;
|
|
||||||
}
|
|
||||||
|
|
||||||
public BigInteger getNonce() {
|
|
||||||
return nonce;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void incrementTheNonce(){
|
|
||||||
nonce = nonce.add(BigInteger.ONE);
|
|
||||||
}
|
|
||||||
|
|
||||||
public BigInteger getBalance() {
|
|
||||||
return balance;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void addToBalance(BigInteger value){
|
|
||||||
balance = balance.add(value);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,12 +1,15 @@
|
||||||
package org.ethereum.core;
|
package org.ethereum.core;
|
||||||
|
|
||||||
import org.ethereum.crypto.HashUtil;
|
import org.ethereum.crypto.HashUtil;
|
||||||
|
import org.ethereum.db.Config;
|
||||||
|
import org.ethereum.trie.Trie;
|
||||||
import org.ethereum.util.ByteUtil;
|
import org.ethereum.util.ByteUtil;
|
||||||
import org.ethereum.util.RLP;
|
import org.ethereum.util.RLP;
|
||||||
import org.ethereum.util.RLPElement;
|
import org.ethereum.util.RLPElement;
|
||||||
import org.ethereum.util.RLPItem;
|
import org.ethereum.util.RLPItem;
|
||||||
import org.ethereum.util.RLPList;
|
import org.ethereum.util.RLPList;
|
||||||
import org.ethereum.util.Utils;
|
import org.ethereum.util.Utils;
|
||||||
|
import org.spongycastle.util.BigIntegers;
|
||||||
|
|
||||||
import java.math.BigInteger;
|
import java.math.BigInteger;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
@ -21,10 +24,8 @@ import java.util.List;
|
||||||
*/
|
*/
|
||||||
public class Block {
|
public class Block {
|
||||||
|
|
||||||
private static int LIMIT_FACTOR = (int) Math.pow(2, 16);
|
/* A scalar value equal to the mininum limit of gas expenditure per block */
|
||||||
private static double EMA_FACTOR = 1.5;
|
private static long MIN_GAS_LIMIT = BigInteger.valueOf(10).pow(4).longValue();
|
||||||
/* A scalar value equal to the current limit of gas expenditure per block */
|
|
||||||
private static int GAS_LIMIT = (int) Math.pow(10, 6);
|
|
||||||
|
|
||||||
private byte[] rlpEncoded;
|
private byte[] rlpEncoded;
|
||||||
private boolean parsed = false;
|
private boolean parsed = false;
|
||||||
|
@ -72,6 +73,7 @@ public class Block {
|
||||||
|
|
||||||
private List<Transaction> transactionsList = new ArrayList<Transaction>();
|
private List<Transaction> transactionsList = new ArrayList<Transaction>();
|
||||||
private List<Block> uncleList = new ArrayList<Block>();
|
private List<Block> uncleList = new ArrayList<Block>();
|
||||||
|
private Trie state;
|
||||||
|
|
||||||
public Block(byte[] rawData) {
|
public Block(byte[] rawData) {
|
||||||
this.rlpEncoded = rawData;
|
this.rlpEncoded = rawData;
|
||||||
|
@ -79,14 +81,15 @@ public class Block {
|
||||||
}
|
}
|
||||||
|
|
||||||
public Block(byte[] parentHash, byte[] unclesHash, byte[] coinbase,
|
public Block(byte[] parentHash, byte[] unclesHash, byte[] coinbase,
|
||||||
byte[] stateRoot, byte[] txTrieRoot, byte[] difficulty,
|
byte[] txTrieRoot, byte[] difficulty, long number,
|
||||||
long number, long minGasPrice, long gasLimit, long gasUsed,
|
long minGasPrice, long gasLimit, long gasUsed, long timestamp,
|
||||||
long timestamp, byte[] extraData, byte[] nonce,
|
byte[] extraData, byte[] nonce, List<Transaction> transactionsList,
|
||||||
List<Transaction> transactionsList, List<Block> uncleList) {
|
List<Block> uncleList) {
|
||||||
this.parentHash = parentHash;
|
this.parentHash = parentHash;
|
||||||
this.unclesHash = unclesHash;
|
this.unclesHash = unclesHash;
|
||||||
this.coinbase = coinbase;
|
this.coinbase = coinbase;
|
||||||
this.stateRoot = stateRoot;
|
this.state = new Trie(Config.STATE_DB.getDb());
|
||||||
|
this.stateRoot = state.getRootHash();
|
||||||
this.txTrieRoot = txTrieRoot;
|
this.txTrieRoot = txTrieRoot;
|
||||||
this.difficulty = difficulty;
|
this.difficulty = difficulty;
|
||||||
this.number = number;
|
this.number = number;
|
||||||
|
@ -107,10 +110,9 @@ public class Block {
|
||||||
private void parseRLP() {
|
private void parseRLP() {
|
||||||
|
|
||||||
RLPList params = (RLPList) RLP.decode2(rlpEncoded);
|
RLPList params = (RLPList) RLP.decode2(rlpEncoded);
|
||||||
|
|
||||||
this.hash = HashUtil.sha3(rlpEncoded);
|
|
||||||
|
|
||||||
RLPList block = (RLPList) params.get(0);
|
RLPList block = (RLPList) params.get(0);
|
||||||
|
|
||||||
|
// Parse Header
|
||||||
RLPList header = (RLPList) block.get(0);
|
RLPList header = (RLPList) block.get(0);
|
||||||
|
|
||||||
this.parentHash = ((RLPItem) header.get(0)).getRLPData();
|
this.parentHash = ((RLPItem) header.get(0)).getRLPData();
|
||||||
|
@ -130,12 +132,12 @@ public class Block {
|
||||||
this.minGasPrice = gpBytes == null ? 0 : (new BigInteger(1, gpBytes)).longValue();
|
this.minGasPrice = gpBytes == null ? 0 : (new BigInteger(1, gpBytes)).longValue();
|
||||||
this.gasLimit = glBytes == null ? 0 : (new BigInteger(1, glBytes)).longValue();
|
this.gasLimit = glBytes == null ? 0 : (new BigInteger(1, glBytes)).longValue();
|
||||||
this.gasUsed = guBytes == null ? 0 : (new BigInteger(1, guBytes)).longValue();
|
this.gasUsed = guBytes == null ? 0 : (new BigInteger(1, guBytes)).longValue();
|
||||||
this.timestamp = tsBytes == null ? 0 : (new BigInteger(tsBytes)).longValue();
|
this.timestamp = tsBytes == null ? 0 : (new BigInteger(1, tsBytes)).longValue();
|
||||||
|
|
||||||
this.extraData = ((RLPItem) header.get(11)).getRLPData();
|
this.extraData = ((RLPItem) header.get(11)).getRLPData();
|
||||||
this.nonce = ((RLPItem) header.get(12)).getRLPData();
|
this.nonce = ((RLPItem) header.get(12)).getRLPData();
|
||||||
|
|
||||||
// parse transactions
|
// Parse Transactions
|
||||||
RLPList transactions = (RLPList) block.get(1);
|
RLPList transactions = (RLPList) block.get(1);
|
||||||
for (RLPElement rlpTx : transactions){
|
for (RLPElement rlpTx : transactions){
|
||||||
|
|
||||||
|
@ -149,13 +151,14 @@ public class Block {
|
||||||
RLPElement txRecipe2 = ((RLPList)rlpTx).get(2);
|
RLPElement txRecipe2 = ((RLPList)rlpTx).get(2);
|
||||||
}
|
}
|
||||||
|
|
||||||
// parse uncles
|
// Parse Uncles
|
||||||
RLPList uncleBlocks = (RLPList) block.get(2);
|
RLPList uncleBlocks = (RLPList) block.get(2);
|
||||||
for (RLPElement rawUncle : uncleBlocks){
|
for (RLPElement rawUncle : uncleBlocks){
|
||||||
Block blockData = new Block(rawUncle.getRLPData());
|
Block blockData = new Block(rawUncle.getRLPData());
|
||||||
this.uncleList.add(blockData);
|
this.uncleList.add(blockData);
|
||||||
}
|
}
|
||||||
this.parsed = true;
|
this.parsed = true;
|
||||||
|
this.hash = this.getHash();
|
||||||
}
|
}
|
||||||
|
|
||||||
public byte[] getHash(){
|
public byte[] getHash(){
|
||||||
|
@ -185,7 +188,7 @@ public class Block {
|
||||||
|
|
||||||
public byte[] getStateRoot() {
|
public byte[] getStateRoot() {
|
||||||
if (!parsed) parseRLP();
|
if (!parsed) parseRLP();
|
||||||
return stateRoot;
|
return this.stateRoot;
|
||||||
}
|
}
|
||||||
|
|
||||||
public byte[] getTxTrieRoot() {
|
public byte[] getTxTrieRoot() {
|
||||||
|
@ -315,30 +318,55 @@ public class Block {
|
||||||
return toStringBuff.toString();
|
return toStringBuff.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public byte[] updateState(byte[] key, byte[] value) {
|
||||||
|
this.state.update(key, value);
|
||||||
|
return this.stateRoot = this.state.getRootHash();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Because every transaction published into the blockchain imposes on the
|
* This mechanism enforces a homeostasis in terms of the time between blocks;
|
||||||
* network the cost of needing to download and verify it, there is a need
|
* a smaller period between the last two blocks results in an increase in the
|
||||||
* for some regulatory mechanism to prevent abuse.
|
* difficulty level and thus additional computation required, lengthening the
|
||||||
*
|
* likely next period. Conversely, if the period is too large, the difficulty,
|
||||||
* To solve this we simply institute a floating cap:
|
* and expected time to the next block, is reduced.
|
||||||
*
|
*/
|
||||||
* No block can have more operations than BLK_LIMIT_FACTOR times
|
private boolean isValid() {
|
||||||
* the long-term exponential moving average.
|
boolean isValid = false;
|
||||||
*
|
|
||||||
* Specifically:
|
// verify difficulty meets requirements
|
||||||
*
|
isValid = this.getDifficulty() == this.calcDifficulty();
|
||||||
* blk.oplimit = floor((blk.parent.oplimit * (EMAFACTOR - 1)
|
// verify gasLimit meets requirements
|
||||||
* + floor(GAS_LIMIT * BLK_LIMIT_FACTOR)) / EMA_FACTOR)
|
isValid = this.getGasLimit() == this.calcGasLimit();
|
||||||
*
|
// verify timestamp meets requirements
|
||||||
* BLK_LIMIT_FACTOR and EMA_FACTOR are constants that will be set
|
isValid = this.getTimestamp() > this.getParent().getTimestamp();
|
||||||
* to 65536 and 1.5 for the time being, but will likely be changed
|
|
||||||
* after further analysis.
|
return isValid;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculate GasLimit
|
||||||
|
* max(10000, (parent gas limit * (1024 - 1) + (parent gas used * 6 / 5)) / 1024)
|
||||||
*
|
*
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public double getOplimit() {
|
public long calcGasLimit() {
|
||||||
return Math.floor((this.getParent().getOplimit() * (EMA_FACTOR - 1)
|
if (parentHash == null)
|
||||||
+ Math.floor(GAS_LIMIT * LIMIT_FACTOR)) / EMA_FACTOR);
|
return 1000000L;
|
||||||
|
else {
|
||||||
|
Block parent = this.getParent();
|
||||||
|
return Math.max(MIN_GAS_LIMIT, (parent.gasLimit * (1024 - 1) + (parent.gasUsed * 6 / 5)) / 1024);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] calcDifficulty() {
|
||||||
|
if (parentHash == null)
|
||||||
|
return Genesis.DIFFICULTY;
|
||||||
|
else {
|
||||||
|
Block parent = this.getParent();
|
||||||
|
long parentDifficulty = new BigInteger(1, parent.difficulty).longValue();
|
||||||
|
long newDifficulty = timestamp >= parent.timestamp + 42 ? parentDifficulty - (parentDifficulty >> 10) : (parentDifficulty + (parentDifficulty >> 10));
|
||||||
|
return BigIntegers.asUnsignedByteArray(BigInteger.valueOf(newDifficulty));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public byte[] getEncoded() {
|
public byte[] getEncoded() {
|
||||||
|
|
|
@ -0,0 +1,142 @@
|
||||||
|
package org.ethereum.core;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.math.BigInteger;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.ethereum.db.Config;
|
||||||
|
import org.ethereum.db.Database;
|
||||||
|
import org.ethereum.net.message.StaticMessages;
|
||||||
|
import org.ethereum.net.submit.PendingTransaction;
|
||||||
|
import org.iq80.leveldb.DBIterator;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.spongycastle.util.encoders.Hex;
|
||||||
|
|
||||||
|
public class Blockchain extends ArrayList<Block> {
|
||||||
|
|
||||||
|
private static Logger logger = LoggerFactory.getLogger(Blockchain.class);
|
||||||
|
|
||||||
|
private Database db;
|
||||||
|
private Wallet wallet;
|
||||||
|
private long gasPrice = 1000;
|
||||||
|
private Block lastBlock = new Genesis();
|
||||||
|
|
||||||
|
private Map<BigInteger, PendingTransaction> pendingTransactions =
|
||||||
|
Collections.synchronizedMap(new HashMap<BigInteger, PendingTransaction>());
|
||||||
|
|
||||||
|
public Blockchain(Wallet wallet) {
|
||||||
|
this.db = Config.CHAIN_DB;
|
||||||
|
this.wallet = wallet;
|
||||||
|
|
||||||
|
DBIterator iterator = db.iterator();
|
||||||
|
try {
|
||||||
|
for (iterator.seekToFirst(); iterator.hasNext(); iterator.next()) {
|
||||||
|
byte[] value = iterator.peekNext().getValue();
|
||||||
|
Block block = new Block(value);
|
||||||
|
if(block.getNumber() > lastBlock.getNumber()) lastBlock = block;
|
||||||
|
this.add(new Block(value));
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
// Make sure you close the iterator to avoid resource leaks.
|
||||||
|
try {
|
||||||
|
iterator.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Block getLastBlock() {
|
||||||
|
return lastBlock;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addBlocks(List<Block> blocks) {
|
||||||
|
|
||||||
|
// TODO: redesign this part when the state part and the genesis block is ready
|
||||||
|
|
||||||
|
if (blocks.isEmpty()) return;
|
||||||
|
|
||||||
|
Block firstBlockToAdd = blocks.get(blocks.size() - 1);
|
||||||
|
|
||||||
|
// if it is the first block to add
|
||||||
|
// check that the parent is the genesis
|
||||||
|
if (this.isEmpty() &&
|
||||||
|
!Arrays.equals(StaticMessages.GENESIS_HASH, firstBlockToAdd.getParentHash())){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// if there is some blocks already keep chain continuity
|
||||||
|
if (!this.isEmpty() ){
|
||||||
|
Block lastBlock = this.get(this.size() - 1);
|
||||||
|
String hashLast = Hex.toHexString(lastBlock.getHash());
|
||||||
|
String blockParentHash = Hex.toHexString(firstBlockToAdd.getParentHash());
|
||||||
|
if (!hashLast.equals(blockParentHash)) return;
|
||||||
|
}
|
||||||
|
for (int i = blocks.size() - 1; i >= 0 ; --i){
|
||||||
|
Block block = blocks.get(i);
|
||||||
|
this.add(block);
|
||||||
|
if(block.getNumber() > lastBlock.getNumber()) lastBlock = block;
|
||||||
|
db.put(block.getHash(), block.getEncoded());
|
||||||
|
if (logger.isDebugEnabled())
|
||||||
|
logger.debug("block added to the chain with hash: {}", Hex.toHexString(block.getHash()));
|
||||||
|
this.gasPrice = block.getMinGasPrice();
|
||||||
|
|
||||||
|
wallet.processBlock(block);
|
||||||
|
}
|
||||||
|
// Remove all pending transactions as they already approved by the net
|
||||||
|
for (Block block : blocks){
|
||||||
|
for (Transaction tx : block.getTransactionsList()){
|
||||||
|
if (logger.isDebugEnabled())
|
||||||
|
logger.debug("pending cleanup: tx.hash: [{}]", Hex.toHexString( tx.getHash()));
|
||||||
|
removePendingTransaction(tx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.info("*** Block chain size: [ {} ]", this.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 1) the dialog put a pending transaction on the list
|
||||||
|
* 2) the dialog send the transaction to a net
|
||||||
|
* 3) wherever the transaction got for the wire in will change to approve state
|
||||||
|
* 4) only after the approve a) Wallet state changes
|
||||||
|
* 5) After the block is received with that tx the pending been clean up
|
||||||
|
*/
|
||||||
|
public PendingTransaction addPendingTransaction(Transaction transaction) {
|
||||||
|
|
||||||
|
BigInteger hash = new BigInteger(transaction.getHash());
|
||||||
|
logger.info("pending transaction placed hash: {} ", hash.toString(16) );
|
||||||
|
|
||||||
|
PendingTransaction pendingTransaction = pendingTransactions.get(hash);
|
||||||
|
if (pendingTransaction != null)
|
||||||
|
pendingTransaction.incApproved();
|
||||||
|
else {
|
||||||
|
pendingTransaction = new PendingTransaction(transaction);
|
||||||
|
pendingTransactions.put(hash, pendingTransaction);
|
||||||
|
}
|
||||||
|
return pendingTransaction;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void removePendingTransaction(Transaction transaction){
|
||||||
|
|
||||||
|
BigInteger hash = new BigInteger(transaction.getHash());
|
||||||
|
logger.info("pending transaction removed with hash: {} ", hash.toString(16) );
|
||||||
|
pendingTransactions.remove(hash);
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getGasPrice() {
|
||||||
|
return gasPrice;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] getLatestBlockHash(){
|
||||||
|
if (this.isEmpty())
|
||||||
|
return StaticMessages.GENESIS_HASH;
|
||||||
|
else
|
||||||
|
return lastBlock.getHash();
|
||||||
|
}
|
||||||
|
}
|
|
@ -16,25 +16,42 @@ public class Genesis extends Block {
|
||||||
private static byte[] zeroHash160 = new byte[20];
|
private static byte[] zeroHash160 = new byte[20];
|
||||||
private static byte[] sha3EmptyList = HashUtil.sha3(RLP.encodeList());
|
private static byte[] sha3EmptyList = HashUtil.sha3(RLP.encodeList());
|
||||||
|
|
||||||
private static byte[] parentHash = zeroHash256;
|
public static byte[] PARENT_HASH = zeroHash256;
|
||||||
private static byte[] unclesHash = sha3EmptyList;
|
public static byte[] UNCLES_HASH = sha3EmptyList;
|
||||||
private static byte[] coinbase = zeroHash160;
|
public static byte[] COINBASE = zeroHash160;
|
||||||
private static byte[] stateRoot = // TODO: Get stateRoot from actual state
|
public static byte[] TX_TRIE_ROOT = new byte[0];
|
||||||
Hex.decode("12582945fc5ad12c3e7b67c4fc37a68fc0d52d995bb7f7291ff41a2739a7ca16");
|
public static byte[] DIFFICULTY = BigInteger.valueOf(2).pow(22).toByteArray();
|
||||||
private static byte[] txTrieRoot = new byte[0];
|
public static long NUMBER = 0;
|
||||||
private static byte[] difficulty = BigInteger.valueOf(2).pow(22).toByteArray();
|
public static long MIN_GAS_PRICE = 0;
|
||||||
private static long number = 0;
|
public static long GAS_LIMIT = 1000000;
|
||||||
private static long minGasPrice = 0;
|
public static long GAS_USED = 0;
|
||||||
private static long gasLimit = 1000000;
|
public static long TIMESTAMP = 0;
|
||||||
private static long gasUsed = 0;
|
public static byte[] EXTRA_DATA = new byte[0];
|
||||||
private static long timestamp = 0;
|
public static byte[] NONCE = HashUtil.sha3(new byte[]{42});
|
||||||
private static byte[] extraData = new byte[0];
|
|
||||||
private static byte[] nonce = HashUtil.sha3(new byte[]{42});
|
|
||||||
|
|
||||||
public Genesis() {
|
public Genesis() {
|
||||||
super(parentHash, unclesHash, coinbase, stateRoot,
|
super(PARENT_HASH, UNCLES_HASH, COINBASE, TX_TRIE_ROOT, DIFFICULTY,
|
||||||
txTrieRoot, difficulty, number, minGasPrice, gasLimit, gasUsed,
|
NUMBER, MIN_GAS_PRICE, GAS_LIMIT, GAS_USED, TIMESTAMP,
|
||||||
timestamp, extraData, nonce, null, null);
|
EXTRA_DATA, NONCE, null, null);
|
||||||
|
// Premine state
|
||||||
|
AccountState acct = new AccountState(BigInteger.ZERO, BigInteger.valueOf(2).pow(200));
|
||||||
|
// # (M)
|
||||||
|
this.updateState(Hex.decode("2ef47100e0787b915105fd5e3f4ff6752079d5cb"), acct.getEncoded());
|
||||||
|
// # (A)
|
||||||
|
this.updateState(Hex.decode("1a26338f0d905e295fccb71fa9ea849ffa12aaf4"), acct.getEncoded());
|
||||||
|
// # (J)
|
||||||
|
this.updateState(Hex.decode("e6716f9544a56c530d868e4bfbacb172315bdead"), acct.getEncoded());
|
||||||
|
// # (G)
|
||||||
|
this.updateState(Hex.decode("8a40bfaa73256b60764c1bf40675a99083efb075"), acct.getEncoded());
|
||||||
|
// # (CH)
|
||||||
|
this.updateState(Hex.decode("e4157b34ea9615cfbde6b4fda419828124b70c78"), acct.getEncoded());
|
||||||
|
// # (V)
|
||||||
|
this.updateState(Hex.decode("1e12515ce3e0f817a4ddef9ca55788a1d66bd2df"), acct.getEncoded());
|
||||||
|
// # (HH)
|
||||||
|
this.updateState(Hex.decode("6c386a4b26f73c802f34673f7248bb118f97424a"), acct.getEncoded());
|
||||||
|
// # (R)
|
||||||
|
this.updateState(Hex.decode("cd2a3d9f938e13cd947ec05abc7fe734df8dd826"), acct.getEncoded());
|
||||||
|
System.out.println(Hex.toHexString(this.getStateRoot()));
|
||||||
logger.info("Genesis-hash: " + Hex.toHexString(this.getHash()));
|
logger.info("Genesis-hash: " + Hex.toHexString(this.getHash()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,160 @@
|
||||||
|
package org.ethereum.core;
|
||||||
|
|
||||||
|
import java.math.BigInteger;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.ethereum.trie.Trie;
|
||||||
|
|
||||||
|
public class GoState {
|
||||||
|
|
||||||
|
// States within the ethereum protocol are used to store anything
|
||||||
|
// within the merkle trie. States take care of caching and storing
|
||||||
|
// nested states. It's the general query interface to retrieve:
|
||||||
|
// * Contracts
|
||||||
|
// * Accounts
|
||||||
|
|
||||||
|
// The trie for this structure
|
||||||
|
private Trie trie;
|
||||||
|
// Nested states
|
||||||
|
private Map<String, GoState> states;
|
||||||
|
|
||||||
|
// Create a new state from a given trie
|
||||||
|
public GoState(Trie trie) {
|
||||||
|
this.trie = trie;
|
||||||
|
states = new HashMap<String, GoState>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void add(String key, GoState state) {
|
||||||
|
this.states.put(key, state);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Resets the trie and all siblings
|
||||||
|
public void reset() {
|
||||||
|
this.trie.undo();
|
||||||
|
|
||||||
|
// Reset all nested states
|
||||||
|
for (GoState state : states.values()) {
|
||||||
|
state.reset();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Syncs the trie and all siblings
|
||||||
|
public void sync() {
|
||||||
|
this.trie.sync();
|
||||||
|
|
||||||
|
// Sync all nested states
|
||||||
|
for (GoState state : states.values()) {
|
||||||
|
state.sync();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Purges the current trie.
|
||||||
|
public int purge() {
|
||||||
|
return this.trie.getIterator().purge();
|
||||||
|
}
|
||||||
|
|
||||||
|
public StateObject getContract(byte[] address) {
|
||||||
|
byte[] data = this.trie.get(new String(address));
|
||||||
|
if (data == null || data.length == 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// build contract
|
||||||
|
StateObject contract = new StateObject(address, data);
|
||||||
|
|
||||||
|
// Check if there's a cached state for this contract
|
||||||
|
GoState cachedState = this.states.get(new String(address));
|
||||||
|
if (cachedState != null) {
|
||||||
|
contract.setState( cachedState );
|
||||||
|
} else {
|
||||||
|
// If it isn't cached, cache the state
|
||||||
|
this.states.put(new String(address), contract.getState());
|
||||||
|
}
|
||||||
|
|
||||||
|
return contract;
|
||||||
|
}
|
||||||
|
|
||||||
|
public StateObject getAccount(byte[] address) {
|
||||||
|
byte[] data = this.trie.get(new String(address));
|
||||||
|
if (data == null || data.length == 0) {
|
||||||
|
return StateObject.createAccount(address, BigInteger.ZERO);
|
||||||
|
} else {
|
||||||
|
return new StateObject(address, data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean cmp(GoState other) {
|
||||||
|
return this.trie.cmp(other.getTrie());
|
||||||
|
}
|
||||||
|
|
||||||
|
public GoState copy() {
|
||||||
|
return new GoState(this.trie.copy());
|
||||||
|
}
|
||||||
|
|
||||||
|
// type ObjType byte
|
||||||
|
//
|
||||||
|
// enum (
|
||||||
|
// NullTy ObjType = iota,
|
||||||
|
// AccountTy,
|
||||||
|
// ContractTy,
|
||||||
|
// UnknownTy
|
||||||
|
// )
|
||||||
|
|
||||||
|
// Returns the object stored at key and the type stored at key
|
||||||
|
// Returns null if nothing is stored
|
||||||
|
// public (*ethutil.Value, ObjType) getStateObject(byte[] key) {
|
||||||
|
//
|
||||||
|
// // Fetch data from the trie
|
||||||
|
// String data = this.trie.get(new String(key));
|
||||||
|
// // Returns the null type, indicating nothing could be retrieved.
|
||||||
|
// // Anything using this function should check for this ret val
|
||||||
|
// if (data == "") {
|
||||||
|
// return (null, NullTy)
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// var enum ObjType
|
||||||
|
// Value val = new Value(data.getBytes());
|
||||||
|
// // Check the length of the retrieved value.
|
||||||
|
// // Len 2 = Account
|
||||||
|
// // Len 3 = Contract
|
||||||
|
// // Other = invalid for now. If other types emerge, add them here
|
||||||
|
// if (val.length() == 2) {
|
||||||
|
// typ = AccountTy
|
||||||
|
// } else if (val.length == 3) {
|
||||||
|
// typ = ContractTy
|
||||||
|
// } else {
|
||||||
|
// typ = UnknownTy
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// return (val, typ);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// Updates any given state object
|
||||||
|
public void updateStateObject(StateObject stateObject) {
|
||||||
|
byte[] addr = stateObject.getAddress();
|
||||||
|
|
||||||
|
if (stateObject.getState() != null) {
|
||||||
|
this.states.put(new String(addr), stateObject.getState());
|
||||||
|
}
|
||||||
|
|
||||||
|
this.trie.update(addr, stateObject.rlpEncode());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void put(byte[] key, byte[] object) {
|
||||||
|
this.trie.update(key, object);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instead of calling this method, call state.getTrie().getRoot()
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
@Deprecated()
|
||||||
|
public Object getRoot() {
|
||||||
|
return this.trie.getRoot();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Trie getTrie() {
|
||||||
|
return this.trie;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,12 @@
|
||||||
|
package org.ethereum.core;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.ethereum.trie.Trie;
|
||||||
|
|
||||||
|
public class State {
|
||||||
|
|
||||||
|
Trie trie;
|
||||||
|
Map<String, State> states;
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,180 @@
|
||||||
|
package org.ethereum.core;
|
||||||
|
|
||||||
|
import java.math.BigInteger;
|
||||||
|
|
||||||
|
import org.ethereum.db.Config;
|
||||||
|
import org.ethereum.trie.Trie;
|
||||||
|
import org.ethereum.util.RLP;
|
||||||
|
import org.ethereum.util.Value;
|
||||||
|
|
||||||
|
import static java.util.Arrays.copyOfRange;
|
||||||
|
|
||||||
|
public class StateObject {
|
||||||
|
|
||||||
|
// Address of the object
|
||||||
|
private byte[] address;
|
||||||
|
// Shared attributes
|
||||||
|
private BigInteger amount;
|
||||||
|
|
||||||
|
private long nonce;
|
||||||
|
// Contract related attributes
|
||||||
|
private GoState state;
|
||||||
|
|
||||||
|
private byte[] init;
|
||||||
|
private byte[] body;
|
||||||
|
|
||||||
|
// Returns a newly created contract at root
|
||||||
|
public static StateObject createContract(byte[] address, BigInteger amount, byte[] root) {
|
||||||
|
StateObject contract = new StateObject(address, amount);
|
||||||
|
contract.setState(new GoState(new Trie(Config.STATE_DB.getDb(), new String(root))));
|
||||||
|
return contract;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns a newly created account
|
||||||
|
public static StateObject createAccount(byte[] address, BigInteger amount) {
|
||||||
|
return new StateObject(address, amount);
|
||||||
|
}
|
||||||
|
|
||||||
|
public StateObject(byte[] address, BigInteger amount) {
|
||||||
|
this.address = address;
|
||||||
|
this.amount = amount;
|
||||||
|
}
|
||||||
|
|
||||||
|
public StateObject(byte[] address, byte[] data) {
|
||||||
|
this.address = address;
|
||||||
|
this.rlpDecode(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setState(GoState state) {
|
||||||
|
this.state = state;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setBody(byte[] body) {
|
||||||
|
this.body = body;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setInit(byte[] init) {
|
||||||
|
this.init = init;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Value getAddress(byte[] address) {
|
||||||
|
return new Value(this.state.getTrie().get(new String(address)));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAddress(byte[] address, Object value) {
|
||||||
|
this.state.getTrie().update(address, new Value(value).encode());
|
||||||
|
}
|
||||||
|
|
||||||
|
public GoState getState() {
|
||||||
|
return this.state;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Value getMem(BigInteger num) {
|
||||||
|
byte[] nb = num.toByteArray();
|
||||||
|
return this.getAddress(nb);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the instruction
|
||||||
|
*
|
||||||
|
* @param pc
|
||||||
|
* @return byte wrapped in a Value object
|
||||||
|
*/
|
||||||
|
public Value getInstr(BigInteger pc) {
|
||||||
|
if (this.body.length-1 < pc.longValue()) {
|
||||||
|
return new Value(0);
|
||||||
|
}
|
||||||
|
return new Value( new byte[] { this.body[pc.intValue()] } );
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMem(BigInteger num, Value val) {
|
||||||
|
byte[] address = num.toByteArray();
|
||||||
|
this.state.getTrie().update(address, val.encode());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return the gas back to the origin. Used by the Virtual machine or Closures
|
||||||
|
public void returnGas(BigInteger gas, BigInteger gasPrice, GoState state) {
|
||||||
|
BigInteger remainder = gas.multiply(gasPrice);
|
||||||
|
this.addAmount(remainder);
|
||||||
|
}
|
||||||
|
|
||||||
|
public BigInteger getAmount() {
|
||||||
|
return this.amount;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addAmount(BigInteger amount) {
|
||||||
|
this.amount = this.amount.add(amount);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void subAmount(BigInteger amount) {
|
||||||
|
this.amount = this.amount.subtract(amount);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void convertGas(BigInteger gas, BigInteger gasPrice) throws RuntimeException {
|
||||||
|
BigInteger total = gas.multiply(gasPrice);
|
||||||
|
if (total.compareTo(this.amount) > 0) {
|
||||||
|
throw new RuntimeException("insufficient amount: " + this.amount + ", " + total);
|
||||||
|
}
|
||||||
|
this.subAmount(total);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns the address of the contract/account
|
||||||
|
public byte[] getAddress() {
|
||||||
|
return this.address;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getNonce() {
|
||||||
|
return this.nonce;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns the main script body
|
||||||
|
public byte[] getBody() {
|
||||||
|
return this.body;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns the initialization script
|
||||||
|
public byte[] getInit() {
|
||||||
|
return this.init;
|
||||||
|
}
|
||||||
|
|
||||||
|
// State object encoding methods
|
||||||
|
public byte[] rlpEncode() {
|
||||||
|
Object root;
|
||||||
|
if (this.state != null) {
|
||||||
|
root = this.state.getTrie().getRoot();
|
||||||
|
} else {
|
||||||
|
root = null;
|
||||||
|
}
|
||||||
|
return RLP.encode( new Object[] {this.amount, this.nonce, root, this.body});
|
||||||
|
}
|
||||||
|
|
||||||
|
public void rlpDecode(byte[] data) {
|
||||||
|
Value decoder = new Value(data);
|
||||||
|
|
||||||
|
this.amount = decoder.get(0).asBigInt();
|
||||||
|
this.nonce = decoder.get(1).asInt();
|
||||||
|
this.state = new GoState(new Trie(Config.STATE_DB.getDb(), decoder.get(2).asObj()));
|
||||||
|
this.body = decoder.get(3).asBytes();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Converts an transaction in to a state object
|
||||||
|
public static StateObject createContract(Transaction tx, GoState state) {
|
||||||
|
// Create contract if there's no recipient
|
||||||
|
if (tx.isContract()) {
|
||||||
|
// FIXME
|
||||||
|
byte[] txHash = tx.getHash();
|
||||||
|
byte[] contractAddress = copyOfRange(txHash, 12, txHash.length);
|
||||||
|
|
||||||
|
BigInteger value = new BigInteger(1, tx.getValue());
|
||||||
|
StateObject contract = StateObject.createContract(contractAddress, value, "".getBytes());
|
||||||
|
state.updateStateObject(contract);
|
||||||
|
|
||||||
|
contract.setBody(tx.getData());
|
||||||
|
|
||||||
|
state.updateStateObject(contract);
|
||||||
|
|
||||||
|
return contract;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,36 @@
|
||||||
|
package org.ethereum.core;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public class StateObjectCache {
|
||||||
|
|
||||||
|
// The cached state and state object cache are helpers which will give you somewhat
|
||||||
|
// control over the nonce. When creating new transactions you're interested in the 'next'
|
||||||
|
// nonce rather than the current nonce. This to avoid creating invalid-nonce transactions.
|
||||||
|
Map<String, CachedStateObject> cachedObjects;
|
||||||
|
|
||||||
|
public StateObjectCache() {
|
||||||
|
this.cachedObjects = new HashMap<String, CachedStateObject>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public CachedStateObject add(byte[] address, StateObject stateObject) {
|
||||||
|
CachedStateObject state = new CachedStateObject(stateObject.getNonce(), stateObject);
|
||||||
|
this.cachedObjects.put(new String(address), state);
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CachedStateObject get(byte[] address) {
|
||||||
|
return this.cachedObjects.get(new String(address));
|
||||||
|
}
|
||||||
|
|
||||||
|
public class CachedStateObject {
|
||||||
|
private long nonce;
|
||||||
|
private StateObject stateObject;
|
||||||
|
|
||||||
|
public CachedStateObject(long nonce, StateObject stateObject) {
|
||||||
|
this.nonce = nonce;
|
||||||
|
this.stateObject = stateObject;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -25,7 +25,7 @@ import java.util.Arrays;
|
||||||
*/
|
*/
|
||||||
public class Transaction {
|
public class Transaction {
|
||||||
|
|
||||||
Logger logger = LoggerFactory.getLogger(this.getClass());
|
private static Logger logger = LoggerFactory.getLogger(Transaction.class);
|
||||||
|
|
||||||
public static final byte[] ZERO_ADDRESS = new byte[20];
|
public static final byte[] ZERO_ADDRESS = new byte[20];
|
||||||
|
|
||||||
|
@ -157,11 +157,6 @@ public class Transaction {
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
public byte[] getInit() {
|
|
||||||
if (!parsed) rlpParse();
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ECDSASignature getSignature() {
|
public ECDSASignature getSignature() {
|
||||||
if (!parsed) rlpParse();
|
if (!parsed) rlpParse();
|
||||||
return signature;
|
return signature;
|
||||||
|
|
|
@ -34,7 +34,7 @@ public class Wallet {
|
||||||
// private HashMap<Address, BigInteger> rows = new HashMap<>();
|
// private HashMap<Address, BigInteger> rows = new HashMap<>();
|
||||||
|
|
||||||
// <address, info> table for a wallet
|
// <address, info> table for a wallet
|
||||||
private HashMap<String, AddressState> rows = new HashMap<String, AddressState>();
|
private HashMap<String, AccountState> rows = new HashMap<String, AccountState>();
|
||||||
private long high;
|
private long high;
|
||||||
|
|
||||||
private List<WalletListener> listeners = new ArrayList<WalletListener>();
|
private List<WalletListener> listeners = new ArrayList<WalletListener>();
|
||||||
|
@ -42,16 +42,14 @@ public class Wallet {
|
||||||
private HashMap<BigInteger, Transaction> transactionMap = new HashMap<BigInteger, Transaction>();
|
private HashMap<BigInteger, Transaction> transactionMap = new HashMap<BigInteger, Transaction>();
|
||||||
|
|
||||||
public void addNewKey(){
|
public void addNewKey(){
|
||||||
|
AccountState addressState = new AccountState();
|
||||||
AddressState addressState = new AddressState();
|
|
||||||
String address = Hex.toHexString(addressState.getEcKey().getAddress());
|
String address = Hex.toHexString(addressState.getEcKey().getAddress());
|
||||||
rows.put(address, addressState);
|
rows.put(address, addressState);
|
||||||
for (WalletListener listener : listeners) listener.valueChanged();
|
for (WalletListener listener : listeners) listener.valueChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void importKey(byte[] privKey){
|
public void importKey(byte[] privKey){
|
||||||
|
AccountState addressState = new AccountState(ECKey.fromPrivate(privKey));
|
||||||
AddressState addressState = new AddressState(ECKey.fromPrivate(privKey));
|
|
||||||
String address = Hex.toHexString(addressState.getEcKey().getAddress());
|
String address = Hex.toHexString(addressState.getEcKey().getAddress());
|
||||||
rows.put(address, addressState);
|
rows.put(address, addressState);
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
|
@ -61,12 +59,11 @@ public class Wallet {
|
||||||
this.listeners.add(walletListener);
|
this.listeners.add(walletListener);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Collection<AddressState> getAddressStateCollection(){
|
public Collection<AccountState> getAddressStateCollection(){
|
||||||
return rows.values();
|
return rows.values();
|
||||||
}
|
}
|
||||||
|
|
||||||
public AddressState getAddressState(byte[] addressBytes){
|
public AccountState getAddressState(byte[] addressBytes){
|
||||||
|
|
||||||
String address = Hex.toHexString(addressBytes);
|
String address = Hex.toHexString(addressBytes);
|
||||||
return rows.get(address);
|
return rows.get(address);
|
||||||
}
|
}
|
||||||
|
@ -78,7 +75,7 @@ public class Wallet {
|
||||||
|
|
||||||
public BigInteger totalBalance(){
|
public BigInteger totalBalance(){
|
||||||
BigInteger sum = BigInteger.ZERO;
|
BigInteger sum = BigInteger.ZERO;
|
||||||
for (AddressState addressState : rows.values()){
|
for (AccountState addressState : rows.values()){
|
||||||
sum = sum.add(addressState.getBalance());
|
sum = sum.add(addressState.getBalance());
|
||||||
}
|
}
|
||||||
return sum;
|
return sum;
|
||||||
|
@ -89,16 +86,16 @@ public class Wallet {
|
||||||
transactionMap.put(new BigInteger(transaction.getHash()), transaction );
|
transactionMap.put(new BigInteger(transaction.getHash()), transaction );
|
||||||
|
|
||||||
byte[] senderAddress = transaction.getSender();
|
byte[] senderAddress = transaction.getSender();
|
||||||
AddressState senderState = rows.get(Hex.toHexString(senderAddress));
|
AccountState senderState = rows.get(Hex.toHexString(senderAddress));
|
||||||
if (senderState != null){
|
if (senderState != null){
|
||||||
|
|
||||||
BigInteger value = new BigInteger(transaction.getValue());
|
BigInteger value = new BigInteger(transaction.getValue());
|
||||||
senderState.addToBalance(value.negate());
|
senderState.addToBalance(value.negate());
|
||||||
senderState.incrementTheNonce();
|
senderState.incrementNonce();
|
||||||
}
|
}
|
||||||
|
|
||||||
byte[] receiveAddress = transaction.getReceiveAddress();
|
byte[] receiveAddress = transaction.getReceiveAddress();
|
||||||
AddressState receiverState = rows.get(Hex.toHexString(receiveAddress));
|
AccountState receiverState = rows.get(Hex.toHexString(receiveAddress));
|
||||||
if (receiverState != null){
|
if (receiverState != null){
|
||||||
receiverState.addToBalance(new BigInteger(1, transaction.getValue()));
|
receiverState.addToBalance(new BigInteger(1, transaction.getValue()));
|
||||||
}
|
}
|
||||||
|
@ -116,12 +113,9 @@ public class Wallet {
|
||||||
List<Transaction> transactions = block.getTransactionsList();
|
List<Transaction> transactions = block.getTransactionsList();
|
||||||
|
|
||||||
for (Transaction tx : transactions){
|
for (Transaction tx : transactions){
|
||||||
|
|
||||||
boolean txExist = transactionMap.get(new BigInteger(tx.getHash())) != null;
|
boolean txExist = transactionMap.get(new BigInteger(tx.getHash())) != null;
|
||||||
if (txExist) break;
|
if (txExist) break;
|
||||||
|
|
||||||
else {
|
else {
|
||||||
|
|
||||||
applyTransaction(tx);
|
applyTransaction(tx);
|
||||||
walletUpdated = true;
|
walletUpdated = true;
|
||||||
}
|
}
|
||||||
|
@ -220,7 +214,7 @@ public class Wallet {
|
||||||
walletElement.setAttributeNode(high);
|
walletElement.setAttributeNode(high);
|
||||||
|
|
||||||
int i = 0;
|
int i = 0;
|
||||||
for (AddressState addressState : getAddressStateCollection()){
|
for (AccountState addressState : getAddressStateCollection()){
|
||||||
|
|
||||||
Element raw = doc.createElement("raw");
|
Element raw = doc.createElement("raw");
|
||||||
Attr id = doc.createAttribute("id");
|
Attr id = doc.createAttribute("id");
|
||||||
|
@ -259,7 +253,8 @@ public class Wallet {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void notifyListeners(){
|
private void notifyListeners(){
|
||||||
for (WalletListener listener : listeners) listener.valueChanged();
|
for (WalletListener listener : listeners)
|
||||||
|
listener.valueChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
public interface WalletListener{
|
public interface WalletListener{
|
||||||
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
package org.ethereum.db;
|
||||||
|
|
||||||
|
public class Config {
|
||||||
|
|
||||||
|
public static Database CHAIN_DB = new Database("blockchain");
|
||||||
|
public static Database STATE_DB = new Database("state");
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,116 @@
|
||||||
|
package org.ethereum.db;
|
||||||
|
|
||||||
|
import static org.iq80.leveldb.impl.Iq80DBFactory.factory;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.ethereum.config.SystemProperties;
|
||||||
|
import org.ethereum.core.Block;
|
||||||
|
import org.iq80.leveldb.DB;
|
||||||
|
import org.iq80.leveldb.DBIterator;
|
||||||
|
import org.iq80.leveldb.Options;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.spongycastle.util.encoders.Hex;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generic interface for Ethereum database
|
||||||
|
*
|
||||||
|
* LevelDB key/value pair DB implementation will be used.
|
||||||
|
* Choice must be made between:
|
||||||
|
* Pure Java: https://github.com/dain/leveldb
|
||||||
|
* JNI binding: https://github.com/fusesource/leveldbjni
|
||||||
|
*/
|
||||||
|
public class Database {
|
||||||
|
|
||||||
|
private static Logger logger = LoggerFactory.getLogger(Database.class);
|
||||||
|
private DB db;
|
||||||
|
|
||||||
|
public Database(String name) {
|
||||||
|
// Initialize Database
|
||||||
|
Options options = new Options();
|
||||||
|
options.createIfMissing(true);
|
||||||
|
try {
|
||||||
|
logger.debug("Opening database");
|
||||||
|
if(SystemProperties.CONFIG.databaseReset()) {
|
||||||
|
logger.debug("Destroying '" + name + "' DB on startup ENABLED");
|
||||||
|
destroyDB(name);
|
||||||
|
}
|
||||||
|
logger.debug("Initializing new or existing DB: '" + name + "'");
|
||||||
|
options.createIfMissing(true);
|
||||||
|
db = factory.open(new File(name), options);
|
||||||
|
printDB();
|
||||||
|
// logger.debug("Showing database stats");
|
||||||
|
// String stats = DATABASE.getProperty("leveldb.stats");
|
||||||
|
// logger.debug(stats);
|
||||||
|
} catch (IOException ioe) {
|
||||||
|
logger.error(ioe.getMessage(), ioe);
|
||||||
|
throw new RuntimeException("Can't initialize database");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void destroyDB(String name) {
|
||||||
|
logger.debug("Destroying existing DB");
|
||||||
|
Options options = new Options();
|
||||||
|
try {
|
||||||
|
factory.destroy(new File(name), options);
|
||||||
|
} catch (IOException e) {
|
||||||
|
logger.error(e.getMessage(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void printDB() {
|
||||||
|
DBIterator iterator = db.iterator();
|
||||||
|
try {
|
||||||
|
Map<Long, Block> blocks = new HashMap<Long, Block>();
|
||||||
|
int count = 0;
|
||||||
|
if (!iterator.hasNext()) {
|
||||||
|
logger.info("DB is empty");
|
||||||
|
} else {
|
||||||
|
logger.info("Displaying blocks stored in DB sorted on key");
|
||||||
|
}
|
||||||
|
for (iterator.seekToFirst(); iterator.hasNext(); iterator.next()) {
|
||||||
|
byte[] key = iterator.peekNext().getKey();
|
||||||
|
byte[] value = iterator.peekNext().getValue();
|
||||||
|
Block block = new Block(value);
|
||||||
|
blocks.put(new Long(block.getNumber()), block);
|
||||||
|
logger.info("Block: " + count + " Key: " + Hex.toHexString(key) + " ---> " + block.toFlatString());
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
// Make sure you close the iterator to avoid resource leaks.
|
||||||
|
try {
|
||||||
|
iterator.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Insert object(value) (key = sha3(value)) */
|
||||||
|
public void put(byte[] key, byte[] value) {
|
||||||
|
db.put(key, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Get object (key) -> value */
|
||||||
|
public byte[] get(byte[] key) {
|
||||||
|
return db.get(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Delete object (key) from db **/
|
||||||
|
public void delete(byte[] key) {
|
||||||
|
delete(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
public DBIterator iterator() {
|
||||||
|
return db.iterator();
|
||||||
|
}
|
||||||
|
|
||||||
|
public DB getDb() {
|
||||||
|
return this.db;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
package org.ethereum.geodb;
|
package org.ethereum.db;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.net.InetAddress;
|
import java.net.InetAddress;
|
|
@ -6,7 +6,6 @@ import org.ethereum.manager.MainData;
|
||||||
import javax.swing.*;
|
import javax.swing.*;
|
||||||
import javax.swing.table.DefaultTableCellRenderer;
|
import javax.swing.table.DefaultTableCellRenderer;
|
||||||
import javax.swing.table.TableCellRenderer;
|
import javax.swing.table.TableCellRenderer;
|
||||||
import javax.tools.Tool;
|
|
||||||
import java.awt.*;
|
import java.awt.*;
|
||||||
import java.awt.datatransfer.Clipboard;
|
import java.awt.datatransfer.Clipboard;
|
||||||
import java.awt.datatransfer.StringSelection;
|
import java.awt.datatransfer.StringSelection;
|
||||||
|
@ -75,9 +74,9 @@ public class BlockChainTable extends JFrame {
|
||||||
@Override
|
@Override
|
||||||
public void actionPerformed(ActionEvent e) {
|
public void actionPerformed(ActionEvent e) {
|
||||||
|
|
||||||
if (MainData.instance.getAllBlocks().size() - 1 < lastFindIndex) return;
|
if (MainData.instance.getBlockchain().size() - 1 < lastFindIndex) return;
|
||||||
|
|
||||||
Block block = MainData.instance.getAllBlocks().get(lastFindIndex);
|
Block block = MainData.instance.getBlockchain().get(lastFindIndex);
|
||||||
StringSelection stsel = new StringSelection(block.toString());
|
StringSelection stsel = new StringSelection(block.toString());
|
||||||
Clipboard system = Toolkit.getDefaultToolkit().getSystemClipboard();
|
Clipboard system = Toolkit.getDefaultToolkit().getSystemClipboard();
|
||||||
system.setContents(stsel,stsel);
|
system.setContents(stsel,stsel);
|
||||||
|
@ -97,10 +96,10 @@ public class BlockChainTable extends JFrame {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = lastFindIndex + 1; i < MainData.instance.getAllBlocks().size(); ++i) {
|
for (int i = lastFindIndex + 1; i < MainData.instance.getBlockchain().size(); ++i) {
|
||||||
|
|
||||||
if (MainData.instance.getAllBlocks().size() - 1 < i) return;
|
if (MainData.instance.getBlockchain().size() - 1 < i) return;
|
||||||
Block block = MainData.instance.getAllBlocks().get(i);
|
Block block = MainData.instance.getBlockchain().get(i);
|
||||||
boolean found = block.toString().toLowerCase().contains(toFind.toLowerCase());
|
boolean found = block.toString().toLowerCase().contains(toFind.toLowerCase());
|
||||||
if (found) {
|
if (found) {
|
||||||
// todo: now we find the first occur
|
// todo: now we find the first occur
|
||||||
|
|
|
@ -15,7 +15,7 @@ public class BlockTableModel extends AbstractTableModel {
|
||||||
public int getRowCount() {
|
public int getRowCount() {
|
||||||
|
|
||||||
fireTableDataChanged();
|
fireTableDataChanged();
|
||||||
int rowCount = MainData.instance.getAllBlocks().size();
|
int rowCount = MainData.instance.getBlockchain().size();
|
||||||
return rowCount;
|
return rowCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -30,6 +30,6 @@ public class BlockTableModel extends AbstractTableModel {
|
||||||
// byte[] hash = MainData.instance.getAllBlocks().get(rowIndex).getHash();
|
// byte[] hash = MainData.instance.getAllBlocks().get(rowIndex).getHash();
|
||||||
// return Hex.toHexString(hash);
|
// return Hex.toHexString(hash);
|
||||||
|
|
||||||
return MainData.instance.getAllBlocks().get(rowIndex).toString();
|
return MainData.instance.getBlockchain().get(rowIndex).toString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,15 +1,10 @@
|
||||||
package org.ethereum.gui;
|
package org.ethereum.gui;
|
||||||
|
|
||||||
import java.awt.*;
|
import java.awt.*;
|
||||||
import java.awt.event.ComponentAdapter;
|
|
||||||
import java.awt.event.ComponentEvent;
|
|
||||||
import java.awt.event.WindowAdapter;
|
import java.awt.event.WindowAdapter;
|
||||||
import java.awt.event.WindowEvent;
|
import java.awt.event.WindowEvent;
|
||||||
import java.net.InetAddress;
|
|
||||||
import java.net.UnknownHostException;
|
|
||||||
|
|
||||||
import javax.swing.*;
|
import javax.swing.*;
|
||||||
import javax.tools.Tool;
|
|
||||||
|
|
||||||
import org.ethereum.config.SystemProperties;
|
import org.ethereum.config.SystemProperties;
|
||||||
import org.ethereum.net.client.ClientPeer;
|
import org.ethereum.net.client.ClientPeer;
|
||||||
|
@ -84,36 +79,13 @@ public class ConnectionConsoleWindow extends JFrame implements PeerListener{
|
||||||
Thread t = new Thread() {
|
Thread t = new Thread() {
|
||||||
public void run() {
|
public void run() {
|
||||||
|
|
||||||
// Peer Server Zero: peer discovery
|
|
||||||
// new ClientPeer(thisConsole).connect("54.201.28.117", 30303);
|
|
||||||
|
|
||||||
// Peer Server One: peer discovery
|
|
||||||
// new ClientPeer(thisConsole).connect("54.204.10.41", 30303);
|
|
||||||
|
|
||||||
// Some dude in Canada
|
|
||||||
// new ClientPeer(thisConsole).connect("131.104.247.135", 30303);
|
|
||||||
|
|
||||||
// Nick
|
|
||||||
// new ClientPeer(thisConsole).connect("82.217.72.169", 30303);
|
|
||||||
|
|
||||||
// c++: ZeroGox
|
|
||||||
// new ClientPeer(thisConsole).connect("54.204.10.41", 30303);
|
|
||||||
|
|
||||||
// RomanJ
|
|
||||||
// new ClientPeer(thisConsole).connect("54.211.14.10", 40404);
|
|
||||||
|
|
||||||
new ClientPeer(thisConsole).connect(SystemProperties.CONFIG.activePeerIP(),
|
new ClientPeer(thisConsole).connect(SystemProperties.CONFIG.activePeerIP(),
|
||||||
SystemProperties.CONFIG.activePeerPort());
|
SystemProperties.CONFIG.activePeerPort());
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
t.start();
|
t.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void console(final String output) {
|
public void console(final String output) {
|
||||||
SwingUtilities.invokeLater(new Runnable() {
|
SwingUtilities.invokeLater(new Runnable() {
|
||||||
|
@ -163,7 +135,6 @@ public class ConnectionConsoleWindow extends JFrame implements PeerListener{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void addCloseAction(){
|
public void addCloseAction(){
|
||||||
this.addWindowListener( new WindowAdapter()
|
this.addWindowListener( new WindowAdapter()
|
||||||
{
|
{
|
||||||
|
@ -176,7 +147,6 @@ public class ConnectionConsoleWindow extends JFrame implements PeerListener{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
// Start all Swing applications on the EDT.
|
// Start all Swing applications on the EDT.
|
||||||
SwingUtilities.invokeLater(new Runnable() {
|
SwingUtilities.invokeLater(new Runnable() {
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
package org.ethereum.gui;
|
package org.ethereum.gui;
|
||||||
|
|
||||||
import org.ethereum.core.AddressState;
|
import org.ethereum.core.AccountState;
|
||||||
import org.ethereum.core.Transaction;
|
import org.ethereum.core.Transaction;
|
||||||
import org.ethereum.manager.MainData;
|
import org.ethereum.manager.MainData;
|
||||||
import org.ethereum.net.client.ClientPeer;
|
import org.ethereum.net.client.ClientPeer;
|
||||||
|
@ -135,10 +135,10 @@ class ContractCallDialog extends JDialog implements MessageAwareDialog{
|
||||||
JComponent editor = (JComponent)(creatorAddressCombo.getEditor().getEditorComponent());
|
JComponent editor = (JComponent)(creatorAddressCombo.getEditor().getEditorComponent());
|
||||||
editor.setForeground(Color.RED);
|
editor.setForeground(Color.RED);
|
||||||
|
|
||||||
Collection<AddressState> addressStates =
|
Collection<AccountState> addressStates =
|
||||||
MainData.instance.getWallet().getAddressStateCollection();
|
MainData.instance.getWallet().getAddressStateCollection();
|
||||||
|
|
||||||
for (AddressState addressState : addressStates){
|
for (AccountState addressState : addressStates){
|
||||||
creatorAddressCombo.addItem(new AddressStateWraper(addressState));
|
creatorAddressCombo.addItem(new AddressStateWraper(addressState));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -229,7 +229,7 @@ class ContractCallDialog extends JDialog implements MessageAwareDialog{
|
||||||
|
|
||||||
byte[] contractAddress = Hex.decode( contractAddrInput.getText());
|
byte[] contractAddress = Hex.decode( contractAddrInput.getText());
|
||||||
|
|
||||||
AddressState addressState = ((AddressStateWraper)creatorAddressCombo.getSelectedItem()).getAddressState();
|
AccountState addressState = ((AddressStateWraper)creatorAddressCombo.getSelectedItem()).getAddressState();
|
||||||
|
|
||||||
byte[] senderPrivKey = addressState.getEcKey().getPrivKeyBytes();
|
byte[] senderPrivKey = addressState.getEcKey().getPrivKeyBytes();
|
||||||
byte[] nonce = addressState.getNonce() == BigInteger.ZERO ? null : addressState.getNonce().toByteArray();
|
byte[] nonce = addressState.getNonce() == BigInteger.ZERO ? null : addressState.getNonce().toByteArray();
|
||||||
|
@ -271,13 +271,13 @@ class ContractCallDialog extends JDialog implements MessageAwareDialog{
|
||||||
|
|
||||||
public class AddressStateWraper {
|
public class AddressStateWraper {
|
||||||
|
|
||||||
private AddressState addressState;
|
private AccountState addressState;
|
||||||
|
|
||||||
public AddressStateWraper(AddressState addressState) {
|
public AddressStateWraper(AccountState addressState) {
|
||||||
this.addressState = addressState;
|
this.addressState = addressState;
|
||||||
}
|
}
|
||||||
|
|
||||||
public AddressState getAddressState() {
|
public AccountState getAddressState() {
|
||||||
return addressState;
|
return addressState;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
package org.ethereum.gui;
|
package org.ethereum.gui;
|
||||||
|
|
||||||
import org.ethereum.core.AddressState;
|
import org.ethereum.core.AccountState;
|
||||||
import org.ethereum.core.Transaction;
|
import org.ethereum.core.Transaction;
|
||||||
import org.ethereum.manager.MainData;
|
import org.ethereum.manager.MainData;
|
||||||
import org.ethereum.net.client.ClientPeer;
|
import org.ethereum.net.client.ClientPeer;
|
||||||
|
@ -143,10 +143,10 @@ class ContractSubmitDialog extends JDialog implements MessageAwareDialog{
|
||||||
JComponent editor = (JComponent)(creatorAddressCombo.getEditor().getEditorComponent());
|
JComponent editor = (JComponent)(creatorAddressCombo.getEditor().getEditorComponent());
|
||||||
editor.setForeground(Color.RED);
|
editor.setForeground(Color.RED);
|
||||||
|
|
||||||
Collection<AddressState> addressStates =
|
Collection<AccountState> addressStates =
|
||||||
MainData.instance.getWallet().getAddressStateCollection();
|
MainData.instance.getWallet().getAddressStateCollection();
|
||||||
|
|
||||||
for (AddressState addressState : addressStates){
|
for (AccountState addressState : addressStates){
|
||||||
|
|
||||||
creatorAddressCombo.addItem(new AddressStateWraper(addressState));
|
creatorAddressCombo.addItem(new AddressStateWraper(addressState));
|
||||||
}
|
}
|
||||||
|
@ -234,7 +234,7 @@ class ContractSubmitDialog extends JDialog implements MessageAwareDialog{
|
||||||
|
|
||||||
public void submitContract(){
|
public void submitContract(){
|
||||||
|
|
||||||
AddressState addressState = ((AddressStateWraper)creatorAddressCombo.getSelectedItem()).getAddressState();
|
AccountState addressState = ((AddressStateWraper)creatorAddressCombo.getSelectedItem()).getAddressState();
|
||||||
|
|
||||||
byte[] senderPrivKey = addressState.getEcKey().getPrivKeyBytes();
|
byte[] senderPrivKey = addressState.getEcKey().getPrivKeyBytes();
|
||||||
byte[] nonce = addressState.getNonce() == BigInteger.ZERO ? null : addressState.getNonce().toByteArray();
|
byte[] nonce = addressState.getNonce() == BigInteger.ZERO ? null : addressState.getNonce().toByteArray();
|
||||||
|
@ -276,7 +276,7 @@ class ContractSubmitDialog extends JDialog implements MessageAwareDialog{
|
||||||
|
|
||||||
public static void main(String args[]) {
|
public static void main(String args[]) {
|
||||||
|
|
||||||
AddressState as = new AddressState();
|
AccountState as = new AccountState();
|
||||||
|
|
||||||
ContractSubmitDialog pod = new ContractSubmitDialog(null, null);
|
ContractSubmitDialog pod = new ContractSubmitDialog(null, null);
|
||||||
pod.setVisible(true);
|
pod.setVisible(true);
|
||||||
|
@ -284,13 +284,13 @@ class ContractSubmitDialog extends JDialog implements MessageAwareDialog{
|
||||||
|
|
||||||
public class AddressStateWraper{
|
public class AddressStateWraper{
|
||||||
|
|
||||||
private AddressState addressState;
|
private AccountState addressState;
|
||||||
|
|
||||||
public AddressStateWraper(AddressState addressState) {
|
public AddressStateWraper(AccountState addressState) {
|
||||||
this.addressState = addressState;
|
this.addressState = addressState;
|
||||||
}
|
}
|
||||||
|
|
||||||
public AddressState getAddressState() {
|
public AccountState getAddressState() {
|
||||||
return addressState;
|
return addressState;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
package org.ethereum.gui;
|
package org.ethereum.gui;
|
||||||
|
|
||||||
import org.ethereum.core.AddressState;
|
import org.ethereum.core.AccountState;
|
||||||
import org.ethereum.core.Transaction;
|
import org.ethereum.core.Transaction;
|
||||||
import org.ethereum.manager.MainData;
|
import org.ethereum.manager.MainData;
|
||||||
import org.ethereum.net.client.ClientPeer;
|
import org.ethereum.net.client.ClientPeer;
|
||||||
|
@ -26,14 +26,14 @@ class PayOutDialog extends JDialog implements MessageAwareDialog{
|
||||||
|
|
||||||
PayOutDialog dialog;
|
PayOutDialog dialog;
|
||||||
|
|
||||||
AddressState addressState = null;
|
AccountState addressState = null;
|
||||||
JLabel statusMsg = null;
|
JLabel statusMsg = null;
|
||||||
|
|
||||||
final JTextField receiverInput;
|
final JTextField receiverInput;
|
||||||
final JTextField amountInput;
|
final JTextField amountInput;
|
||||||
final JTextField feeInput;
|
final JTextField feeInput;
|
||||||
|
|
||||||
public PayOutDialog(Frame parent, final AddressState addressState) {
|
public PayOutDialog(Frame parent, final AccountState addressState) {
|
||||||
super(parent, "Payout details: ", false);
|
super(parent, "Payout details: ", false);
|
||||||
dialog = this;
|
dialog = this;
|
||||||
|
|
||||||
|
@ -115,7 +115,7 @@ class PayOutDialog extends JDialog implements MessageAwareDialog{
|
||||||
byte[] senderPrivKey = addressState.getEcKey().getPrivKeyBytes();
|
byte[] senderPrivKey = addressState.getEcKey().getPrivKeyBytes();
|
||||||
byte[] nonce = addressState.getNonce() == BigInteger.ZERO ? null : addressState.getNonce().toByteArray();
|
byte[] nonce = addressState.getNonce() == BigInteger.ZERO ? null : addressState.getNonce().toByteArray();
|
||||||
|
|
||||||
byte[] gasPrice = BigInteger.valueOf( MainData.instance.getGasPrice()).toByteArray();
|
byte[] gasPrice = BigInteger.valueOf( MainData.instance.getBlockchain().getGasPrice()).toByteArray();
|
||||||
|
|
||||||
Transaction tx = new Transaction(nonce, gasPrice, BigIntegers
|
Transaction tx = new Transaction(nonce, gasPrice, BigIntegers
|
||||||
.asUnsignedByteArray(fee), address, BigIntegers
|
.asUnsignedByteArray(fee), address, BigIntegers
|
||||||
|
@ -192,7 +192,7 @@ class PayOutDialog extends JDialog implements MessageAwareDialog{
|
||||||
// check if the tx is affordable
|
// check if the tx is affordable
|
||||||
BigInteger ammountValue = new BigInteger(amountText);
|
BigInteger ammountValue = new BigInteger(amountText);
|
||||||
BigInteger feeValue = new BigInteger(feeText);
|
BigInteger feeValue = new BigInteger(feeText);
|
||||||
BigInteger gasPrice = BigInteger.valueOf(MainData.instance.getGasPrice());
|
BigInteger gasPrice = BigInteger.valueOf(MainData.instance.getBlockchain().getGasPrice());
|
||||||
BigInteger currentBalance = addressState.getBalance();
|
BigInteger currentBalance = addressState.getBalance();
|
||||||
|
|
||||||
boolean canAfford = gasPrice.multiply(feeValue).add(ammountValue).compareTo(currentBalance) != 1;
|
boolean canAfford = gasPrice.multiply(feeValue).add(ammountValue).compareTo(currentBalance) != 1;
|
||||||
|
@ -260,7 +260,7 @@ class PayOutDialog extends JDialog implements MessageAwareDialog{
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void main(String args[]) {
|
public static void main(String args[]) {
|
||||||
AddressState as = new AddressState();
|
AccountState as = new AccountState();
|
||||||
PayOutDialog pod = new PayOutDialog(null, as);
|
PayOutDialog pod = new PayOutDialog(null, as);
|
||||||
pod.setVisible(true);
|
pod.setVisible(true);
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,7 @@ import java.util.*;
|
||||||
import javax.swing.ImageIcon;
|
import javax.swing.ImageIcon;
|
||||||
import javax.swing.table.AbstractTableModel;
|
import javax.swing.table.AbstractTableModel;
|
||||||
|
|
||||||
import org.ethereum.geodb.IpGeoDB;
|
import org.ethereum.db.IpGeoDB;
|
||||||
import org.ethereum.manager.MainData;
|
import org.ethereum.manager.MainData;
|
||||||
import org.ethereum.net.client.PeerData;
|
import org.ethereum.net.client.PeerData;
|
||||||
import org.ethereum.util.Utils;
|
import org.ethereum.util.Utils;
|
||||||
|
|
|
@ -1,13 +1,11 @@
|
||||||
package org.ethereum.gui;
|
package org.ethereum.gui;
|
||||||
|
|
||||||
import org.apache.log4j.PropertyConfigurator;
|
|
||||||
import org.ethereum.manager.MainData;
|
import org.ethereum.manager.MainData;
|
||||||
import org.ethereum.util.Utils;
|
import org.ethereum.util.Utils;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import javax.swing.*;
|
import javax.swing.*;
|
||||||
import javax.tools.Tool;
|
|
||||||
|
|
||||||
import java.awt.*;
|
import java.awt.*;
|
||||||
import java.awt.event.ItemEvent;
|
import java.awt.event.ItemEvent;
|
||||||
|
@ -20,7 +18,6 @@ import java.awt.event.ItemListener;
|
||||||
*/
|
*/
|
||||||
public class ToolBar extends JFrame {
|
public class ToolBar extends JFrame {
|
||||||
|
|
||||||
|
|
||||||
Logger logger = LoggerFactory.getLogger(getClass());
|
Logger logger = LoggerFactory.getLogger(getClass());
|
||||||
Logger introLogger = LoggerFactory.getLogger("Intro");
|
Logger introLogger = LoggerFactory.getLogger("Intro");
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
package org.ethereum.gui;
|
package org.ethereum.gui;
|
||||||
|
|
||||||
import org.ethereum.core.AddressState;
|
import org.ethereum.core.AccountState;
|
||||||
import org.ethereum.util.Utils;
|
import org.ethereum.util.Utils;
|
||||||
import org.spongycastle.util.encoders.Hex;
|
import org.spongycastle.util.encoders.Hex;
|
||||||
|
|
||||||
|
@ -21,7 +21,7 @@ import java.net.URL;
|
||||||
*/
|
*/
|
||||||
public class WalletAddressPanel extends JPanel{
|
public class WalletAddressPanel extends JPanel{
|
||||||
|
|
||||||
public WalletAddressPanel(final AddressState addressState) {
|
public WalletAddressPanel(final AccountState addressState) {
|
||||||
|
|
||||||
final WalletAddressPanel walletAddressPanel = this;
|
final WalletAddressPanel walletAddressPanel = this;
|
||||||
|
|
||||||
|
|
|
@ -1,11 +1,10 @@
|
||||||
package org.ethereum.gui;
|
package org.ethereum.gui;
|
||||||
|
|
||||||
import org.ethereum.core.AddressState;
|
import org.ethereum.core.AccountState;
|
||||||
import org.ethereum.core.Wallet;
|
import org.ethereum.core.Wallet;
|
||||||
import org.ethereum.manager.MainData;
|
import org.ethereum.manager.MainData;
|
||||||
|
|
||||||
import javax.swing.*;
|
import javax.swing.*;
|
||||||
import javax.tools.Tool;
|
|
||||||
|
|
||||||
import java.awt.*;
|
import java.awt.*;
|
||||||
import java.awt.event.MouseAdapter;
|
import java.awt.event.MouseAdapter;
|
||||||
|
@ -57,7 +56,7 @@ public class WalletWindow extends JFrame implements Wallet.WalletListener{
|
||||||
|
|
||||||
Wallet wallet = MainData.instance.getWallet();
|
Wallet wallet = MainData.instance.getWallet();
|
||||||
|
|
||||||
for (AddressState addressState : wallet.getAddressStateCollection()){
|
for (AccountState addressState : wallet.getAddressStateCollection()){
|
||||||
|
|
||||||
WalletAddressPanel rowPanel =
|
WalletAddressPanel rowPanel =
|
||||||
new WalletAddressPanel(addressState);
|
new WalletAddressPanel(addressState);
|
||||||
|
|
|
@ -1,29 +1,27 @@
|
||||||
package org.ethereum.manager;
|
package org.ethereum.manager;
|
||||||
|
|
||||||
|
import static org.ethereum.config.SystemProperties.CONFIG;
|
||||||
|
|
||||||
import java.math.BigInteger;
|
import java.math.BigInteger;
|
||||||
import java.net.InetAddress;
|
import java.net.InetAddress;
|
||||||
import java.net.UnknownHostException;
|
import java.net.UnknownHostException;
|
||||||
import java.util.*;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
import com.maxmind.geoip.Location;
|
import org.ethereum.core.AccountState;
|
||||||
|
import org.ethereum.core.Blockchain;
|
||||||
import org.ethereum.core.AddressState;
|
|
||||||
import org.ethereum.core.Block;
|
|
||||||
import org.ethereum.core.Transaction;
|
|
||||||
import org.ethereum.core.Wallet;
|
import org.ethereum.core.Wallet;
|
||||||
import org.ethereum.crypto.ECKey;
|
import org.ethereum.crypto.ECKey;
|
||||||
import org.ethereum.crypto.HashUtil;
|
import org.ethereum.crypto.HashUtil;
|
||||||
import org.ethereum.geodb.IpGeoDB;
|
import org.ethereum.db.IpGeoDB;
|
||||||
import org.ethereum.net.client.ClientPeer;
|
import org.ethereum.net.client.ClientPeer;
|
||||||
import org.ethereum.net.client.PeerData;
|
import org.ethereum.net.client.PeerData;
|
||||||
import org.ethereum.net.message.StaticMessages;
|
|
||||||
import org.ethereum.net.peerdiscovery.PeerDiscovery;
|
import org.ethereum.net.peerdiscovery.PeerDiscovery;
|
||||||
import org.ethereum.net.submit.PendingTransaction;
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.spongycastle.util.encoders.Hex;
|
|
||||||
|
|
||||||
import static org.ethereum.config.SystemProperties.CONFIG;
|
import com.maxmind.geoip.Location;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* www.ethereumJ.com
|
* www.ethereumJ.com
|
||||||
|
@ -35,103 +33,42 @@ public class MainData {
|
||||||
Logger logger = LoggerFactory.getLogger(getClass().getName());
|
Logger logger = LoggerFactory.getLogger(getClass().getName());
|
||||||
|
|
||||||
private List<PeerData> peers = Collections.synchronizedList(new ArrayList<PeerData>());
|
private List<PeerData> peers = Collections.synchronizedList(new ArrayList<PeerData>());
|
||||||
private List<Block> blockChainDB = new ArrayList<Block>();
|
private Blockchain blockChain;
|
||||||
private Wallet wallet = new Wallet();
|
private Wallet wallet = new Wallet();
|
||||||
private ClientPeer activePeer;
|
private ClientPeer activePeer;
|
||||||
|
|
||||||
private long gasPrice = 1000;
|
|
||||||
|
|
||||||
private Map<BigInteger, PendingTransaction> pendingTransactions =
|
|
||||||
Collections.synchronizedMap(new HashMap<BigInteger, PendingTransaction>());
|
|
||||||
|
|
||||||
PeerDiscovery peerDiscovery;
|
PeerDiscovery peerDiscovery;
|
||||||
|
|
||||||
public static MainData instance = new MainData();
|
public static MainData instance = new MainData();
|
||||||
|
|
||||||
public MainData() {
|
public MainData() {
|
||||||
|
// Initialize Wallet
|
||||||
InetAddress ip = null;
|
|
||||||
int port = 0;
|
|
||||||
try {
|
|
||||||
ip = InetAddress.getByName(CONFIG.peerDiscoveryIP());
|
|
||||||
port = CONFIG.peerDiscoveryPort();
|
|
||||||
} catch (UnknownHostException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
System.exit(-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
PeerData peer = new PeerData(
|
|
||||||
ip.getAddress(), port, new byte[]{00});
|
|
||||||
peers.add(peer);
|
|
||||||
|
|
||||||
byte[] cowAddr = HashUtil.sha3("cow".getBytes());
|
byte[] cowAddr = HashUtil.sha3("cow".getBytes());
|
||||||
ECKey key = ECKey.fromPrivate(cowAddr);
|
ECKey key = ECKey.fromPrivate(cowAddr);
|
||||||
|
|
||||||
wallet.importKey(cowAddr);
|
wallet.importKey(cowAddr);
|
||||||
AddressState state = wallet.getAddressState(key.getAddress());
|
AccountState state = wallet.getAddressState(key.getAddress());
|
||||||
state.addToBalance(BigInteger.valueOf(2).pow(200)); // 1606938044258990275541962092341162602522202993782792835301376
|
state.addToBalance(BigInteger.valueOf(2).pow(200)); // 1606938044258990275541962092341162602522202993782792835301376
|
||||||
wallet.importKey(HashUtil.sha3("cat".getBytes()));
|
wallet.importKey(HashUtil.sha3("cat".getBytes()));
|
||||||
|
|
||||||
|
// Initialize Blockchain
|
||||||
|
blockChain = new Blockchain(wallet);
|
||||||
|
|
||||||
|
// Initialize PeerData
|
||||||
|
try {
|
||||||
|
InetAddress ip = InetAddress.getByName(CONFIG.peerDiscoveryIP());
|
||||||
|
int port = CONFIG.peerDiscoveryPort();
|
||||||
|
PeerData peer = new PeerData(ip.getAddress(), port, new byte[]{00});
|
||||||
|
peers.add(peer);
|
||||||
peerDiscovery = new PeerDiscovery(peers);
|
peerDiscovery = new PeerDiscovery(peers);
|
||||||
}
|
} catch (UnknownHostException e) {
|
||||||
|
e.printStackTrace();
|
||||||
public void addBlocks(List<Block> blocks) {
|
System.exit(-1);
|
||||||
|
|
||||||
// TODO: redesign this part when the state part and the genesis block is ready
|
|
||||||
|
|
||||||
if (blocks.isEmpty()) return;
|
|
||||||
|
|
||||||
Block firstBlockToAdd = blocks.get(blocks.size() - 1);
|
|
||||||
|
|
||||||
// if it is the first block to add
|
|
||||||
// check that the parent is the genesis
|
|
||||||
if (blockChainDB.isEmpty() &&
|
|
||||||
!Arrays.equals(StaticMessages.GENESIS_HASH, firstBlockToAdd.getParentHash())){
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// if there is some blocks already
|
|
||||||
// keep chain continuity
|
|
||||||
if (!blockChainDB.isEmpty() ){
|
|
||||||
Block lastBlock = blockChainDB.get(blockChainDB.size() - 1);
|
|
||||||
String hashLast = Hex.toHexString(lastBlock.getHash());
|
|
||||||
String blockParentHash = Hex.toHexString(firstBlockToAdd.getParentHash());
|
|
||||||
if (!hashLast.equals(blockParentHash)) return;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = blocks.size() - 1; i >= 0 ; --i){
|
|
||||||
Block block = blocks.get(i);
|
|
||||||
blockChainDB.add(block);
|
|
||||||
|
|
||||||
if (logger.isInfoEnabled())
|
|
||||||
logger.info("block added to the chain hash: {}", Hex.toHexString(block.getHash()));
|
|
||||||
|
|
||||||
this.gasPrice = block.getMinGasPrice();
|
|
||||||
|
|
||||||
|
|
||||||
wallet.processBlock(block);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Remove all pending transactions as they already approved by the net
|
|
||||||
for (Block block : blocks){
|
|
||||||
for (Transaction tx : block.getTransactionsList()){
|
|
||||||
if (logger.isDebugEnabled())
|
|
||||||
logger.debug("pending cleanup: tx.hash: [{}]", Hex.toHexString( tx.getHash()));
|
|
||||||
removePendingTransaction(tx);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
logger.info("*** Block chain size: [ {} ]", blockChainDB.size());
|
|
||||||
}
|
|
||||||
|
|
||||||
public byte[] getLatestBlockHash(){
|
public Blockchain getBlockchain() {
|
||||||
if (blockChainDB.isEmpty())
|
return blockChain;
|
||||||
return StaticMessages.GENESIS_HASH;
|
|
||||||
else
|
|
||||||
return blockChainDB.get(blockChainDB.size() - 1).getHash();
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<Block> getAllBlocks(){
|
|
||||||
return blockChainDB;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Wallet getWallet() {
|
public Wallet getWallet() {
|
||||||
|
@ -146,39 +83,6 @@ public class MainData {
|
||||||
return activePeer;
|
return activePeer;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* 1) the dialog put a pending transaction on the list
|
|
||||||
* 2) the dialog send the transaction to a net
|
|
||||||
* 3) wherever the transaction got for the wire in will change to approve state
|
|
||||||
* 4) only after the approve a) Wallet state changes
|
|
||||||
* 5) After the block is received with that tx the pending been clean up
|
|
||||||
*/
|
|
||||||
public PendingTransaction addPendingTransaction(Transaction transaction) {
|
|
||||||
|
|
||||||
BigInteger hash = new BigInteger(transaction.getHash());
|
|
||||||
logger.info("pending transaction placed hash: {} ", hash.toString(16) );
|
|
||||||
|
|
||||||
PendingTransaction pendingTransaction = pendingTransactions.get(hash);
|
|
||||||
if (pendingTransaction != null)
|
|
||||||
pendingTransaction.incApproved();
|
|
||||||
else {
|
|
||||||
pendingTransaction = new PendingTransaction(transaction);
|
|
||||||
pendingTransactions.put(hash, pendingTransaction);
|
|
||||||
}
|
|
||||||
return pendingTransaction;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void removePendingTransaction(Transaction transaction){
|
|
||||||
|
|
||||||
BigInteger hash = new BigInteger(transaction.getHash());
|
|
||||||
logger.info("pending transaction removed hash: {} ", hash.toString(16) );
|
|
||||||
pendingTransactions.remove(hash);
|
|
||||||
}
|
|
||||||
|
|
||||||
public long getGasPrice() {
|
|
||||||
return gasPrice;
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<PeerData> getPeers() {
|
public List<PeerData> getPeers() {
|
||||||
return peers;
|
return peers;
|
||||||
}
|
}
|
||||||
|
|
|
@ -202,7 +202,7 @@ public class EthereumProtocolHandler extends ChannelInboundHandlerAdapter {
|
||||||
RLPList rlpList = RLP.decode2(payload);
|
RLPList rlpList = RLP.decode2(payload);
|
||||||
TransactionsMessage transactionsMessage = new TransactionsMessage(rlpList);
|
TransactionsMessage transactionsMessage = new TransactionsMessage(rlpList);
|
||||||
for (Transaction tx : transactionsMessage.getTransactions())
|
for (Transaction tx : transactionsMessage.getTransactions())
|
||||||
MainData.instance.addPendingTransaction(tx);
|
MainData.instance.getBlockchain().addPendingTransaction(tx);
|
||||||
|
|
||||||
// todo: if you got transactions send it to your connected peers
|
// todo: if you got transactions send it to your connected peers
|
||||||
logger.info(transactionsMessage.toString());
|
logger.info(transactionsMessage.toString());
|
||||||
|
@ -256,7 +256,7 @@ public class EthereumProtocolHandler extends ChannelInboundHandlerAdapter {
|
||||||
}, 3000, secToAskForChain * 1000);
|
}, 3000, secToAskForChain * 1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
MainData.instance.addBlocks(blockList);
|
MainData.instance.getBlockchain().addBlocks(blockList);
|
||||||
logger.info(blocksMessage.toString());
|
logger.info(blocksMessage.toString());
|
||||||
if (peerListener != null) peerListener.console(blocksMessage.toString());
|
if (peerListener != null) peerListener.console(blocksMessage.toString());
|
||||||
}
|
}
|
||||||
|
@ -343,7 +343,7 @@ public class EthereumProtocolHandler extends ChannelInboundHandlerAdapter {
|
||||||
|
|
||||||
private void sendGetChain(ChannelHandlerContext ctx){
|
private void sendGetChain(ChannelHandlerContext ctx){
|
||||||
|
|
||||||
byte[] hash = MainData.instance.getLatestBlockHash();
|
byte[] hash = MainData.instance.getBlockchain().getLatestBlockHash();
|
||||||
GetChainMessage chainMessage = new GetChainMessage((byte)100, hash);
|
GetChainMessage chainMessage = new GetChainMessage((byte)100, hash);
|
||||||
|
|
||||||
ByteBuf buffer = ctx.alloc().buffer(chainMessage.getPayload().length + 8);
|
ByteBuf buffer = ctx.alloc().buffer(chainMessage.getPayload().length + 8);
|
||||||
|
|
|
@ -34,7 +34,8 @@ public class TransactionTask implements Callable<Transaction> {
|
||||||
|
|
||||||
ClientPeer peer = MainData.instance.getActivePeer();
|
ClientPeer peer = MainData.instance.getActivePeer();
|
||||||
|
|
||||||
PendingTransaction pendingTransaction = MainData.instance.addPendingTransaction(tx);
|
PendingTransaction pendingTransaction = MainData.instance
|
||||||
|
.getBlockchain().addPendingTransaction(tx);
|
||||||
peer.sendTransaction(tx);
|
peer.sendTransaction(tx);
|
||||||
|
|
||||||
while(pendingTransaction.getApproved() < 1 ){
|
while(pendingTransaction.getApproved() < 1 ){
|
||||||
|
@ -44,7 +45,7 @@ public class TransactionTask implements Callable<Transaction> {
|
||||||
logger.info("return approved: {}", pendingTransaction.getApproved());
|
logger.info("return approved: {}", pendingTransaction.getApproved());
|
||||||
} catch (Throwable th) {
|
} catch (Throwable th) {
|
||||||
logger.info("exception caugh: {}", th.getCause());
|
logger.info("exception caugh: {}", th.getCause());
|
||||||
MainData.instance.removePendingTransaction(tx);
|
MainData.instance.getBlockchain().removePendingTransaction(tx);
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
|
|
|
@ -1,9 +1,5 @@
|
||||||
package org.ethereum.trie;
|
package org.ethereum.trie;
|
||||||
|
|
||||||
import static org.iq80.leveldb.impl.Iq80DBFactory.factory;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
@ -11,7 +7,6 @@ import java.util.Map;
|
||||||
import org.ethereum.crypto.HashUtil;
|
import org.ethereum.crypto.HashUtil;
|
||||||
import org.ethereum.util.Value;
|
import org.ethereum.util.Value;
|
||||||
import org.iq80.leveldb.DB;
|
import org.iq80.leveldb.DB;
|
||||||
import org.iq80.leveldb.Options;
|
|
||||||
|
|
||||||
public class Cache {
|
public class Cache {
|
||||||
|
|
||||||
|
@ -20,21 +15,16 @@ public class Cache {
|
||||||
private boolean isDirty;
|
private boolean isDirty;
|
||||||
|
|
||||||
public Cache(DB db) {
|
public Cache(DB db) {
|
||||||
if(db == null) {
|
|
||||||
try {
|
|
||||||
/* **** Experimental LevelDB Code **** */
|
|
||||||
Options options = new Options();
|
|
||||||
options.createIfMissing(true);
|
|
||||||
this.db = factory.open(new File("ethereumdb"), options);
|
|
||||||
/* **** Experimental LevelDB Code **** */
|
|
||||||
} catch (IOException ioe) {
|
|
||||||
ioe.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
this.db = db;
|
this.db = db;
|
||||||
nodes = new HashMap<byte[], Node>();
|
nodes = new HashMap<byte[], Node>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Put the node in the cache if RLP encoded value is longer than 32 bytes
|
||||||
|
*
|
||||||
|
* @param o the Node which could be a pair-, multi-item Node or single Value
|
||||||
|
* @return sha3 hash of RLP encoded node if length > 32 otherwise return node itself
|
||||||
|
*/
|
||||||
public Object put(Object o) {
|
public Object put(Object o) {
|
||||||
Value value = new Value(o);
|
Value value = new Value(o);
|
||||||
byte[] enc = value.encode();
|
byte[] enc = value.encode();
|
||||||
|
|
|
@ -9,7 +9,6 @@ import java.util.Arrays;
|
||||||
import org.ethereum.crypto.HashUtil;
|
import org.ethereum.crypto.HashUtil;
|
||||||
import org.ethereum.util.Value;
|
import org.ethereum.util.Value;
|
||||||
import org.iq80.leveldb.DB;
|
import org.iq80.leveldb.DB;
|
||||||
import org.spongycastle.util.encoders.Hex;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The modified Merkle Patricia tree (trie) provides a persistent data structure
|
* The modified Merkle Patricia tree (trie) provides a persistent data structure
|
||||||
|
@ -82,10 +81,20 @@ public class Trie {
|
||||||
* @param value
|
* @param value
|
||||||
*/
|
*/
|
||||||
public void update(String key, String value) {
|
public void update(String key, String value) {
|
||||||
|
this.update(key.getBytes(), value.getBytes());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Insert key/value pair into trie
|
||||||
|
*
|
||||||
|
* @param key
|
||||||
|
* @param value
|
||||||
|
*/
|
||||||
|
public void update(byte[] key, byte[] value) {
|
||||||
if (key == null)
|
if (key == null)
|
||||||
throw new NullPointerException("Key should not be blank");
|
throw new NullPointerException("Key should not be blank");
|
||||||
byte[] k = binToNibbles(key.getBytes());
|
byte[] k = binToNibbles(key);
|
||||||
this.root = this.insertOrDelete(this.root, k, value.getBytes());
|
this.root = this.insertOrDelete(this.root, k, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -94,10 +103,10 @@ public class Trie {
|
||||||
* @param key
|
* @param key
|
||||||
* @return value
|
* @return value
|
||||||
*/
|
*/
|
||||||
public String get(String key) {
|
public byte[] get(String key) {
|
||||||
byte[] k = binToNibbles(key.getBytes());
|
byte[] k = binToNibbles(key.getBytes());
|
||||||
Value c = new Value( this.get(this.root, k) );
|
Value c = new Value( this.get(this.root, k) );
|
||||||
return c.asString();
|
return c.asBytes();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -106,7 +115,7 @@ public class Trie {
|
||||||
* @param key
|
* @param key
|
||||||
*/
|
*/
|
||||||
public void delete(String key) {
|
public void delete(String key) {
|
||||||
this.update(key, "");
|
this.update(key.getBytes(), "".getBytes());
|
||||||
}
|
}
|
||||||
|
|
||||||
/****************************************
|
/****************************************
|
||||||
|
@ -322,7 +331,7 @@ public class Trie {
|
||||||
|
|
||||||
// Simple compare function which compared the tries based on their stateRoot
|
// Simple compare function which compared the tries based on their stateRoot
|
||||||
public boolean cmp(Trie trie) {
|
public boolean cmp(Trie trie) {
|
||||||
return this.getRootHash().equals(trie.getRootHash());
|
return Arrays.equals(this.getRootHash(), trie.getRootHash());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Save the cached value to the database.
|
// Save the cached value to the database.
|
||||||
|
@ -368,19 +377,18 @@ public class Trie {
|
||||||
return slice;
|
return slice;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getRootHash() {
|
public byte[] getRootHash() {
|
||||||
Object root = this.getRoot();
|
Object root = this.getRoot();
|
||||||
if (root == null
|
if (root == null
|
||||||
|| (root instanceof byte[] && ((byte[]) root).length == 0)
|
|| (root instanceof byte[] && ((byte[]) root).length == 0)
|
||||||
|| (root instanceof String && "".equals((String) root))) {
|
|| (root instanceof String && "".equals((String) root))) {
|
||||||
return "";
|
return new byte[0];
|
||||||
} else if (root instanceof byte[]) {
|
} else if (root instanceof byte[]) {
|
||||||
return Hex.toHexString((byte[])this.getRoot());
|
return (byte[]) this.getRoot();
|
||||||
} else {
|
} else {
|
||||||
Value rootValue = new Value(this.getRoot());
|
Value rootValue = new Value(this.getRoot());
|
||||||
byte[] val = rootValue.encode();
|
byte[] val = rootValue.encode();
|
||||||
byte[] key = HashUtil.sha3(val);
|
return HashUtil.sha3(val);
|
||||||
return Hex.toHexString(key);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,8 @@ package org.ethereum.util;
|
||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
import org.spongycastle.util.encoders.Hex;
|
||||||
|
|
||||||
public class DecodeResult implements Serializable {
|
public class DecodeResult implements Serializable {
|
||||||
|
|
||||||
private int pos;
|
private int pos;
|
||||||
|
@ -18,4 +20,23 @@ public class DecodeResult implements Serializable {
|
||||||
public Object getDecoded() {
|
public Object getDecoded() {
|
||||||
return decoded;
|
return decoded;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String toString() {
|
||||||
|
return asString(this.decoded);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String asString(Object decoded) {
|
||||||
|
if(decoded instanceof String) {
|
||||||
|
return (String) decoded;
|
||||||
|
} else if (decoded instanceof byte[]) {
|
||||||
|
return Hex.toHexString((byte[]) decoded);
|
||||||
|
} else if (decoded instanceof Object[]) {
|
||||||
|
String result = "";
|
||||||
|
for (Object item : (Object[]) decoded) {
|
||||||
|
result += asString(item);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
throw new RuntimeException("Not a valid type. Should not occur");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,7 @@ import java.util.Queue;
|
||||||
import static java.util.Arrays.copyOfRange;
|
import static java.util.Arrays.copyOfRange;
|
||||||
import static org.ethereum.util.ByteUtil.byteArrayToInt;
|
import static org.ethereum.util.ByteUtil.byteArrayToInt;
|
||||||
import static org.spongycastle.util.Arrays.concatenate;
|
import static org.spongycastle.util.Arrays.concatenate;
|
||||||
|
import static org.spongycastle.util.BigIntegers.asUnsignedByteArray;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
@ -233,7 +234,7 @@ public class RLP {
|
||||||
}
|
}
|
||||||
byte[] valueBytes = new byte[length];
|
byte[] valueBytes = new byte[length];
|
||||||
System.arraycopy(data, index, valueBytes, 0, length);
|
System.arraycopy(data, index, valueBytes, 0, length);
|
||||||
value = new BigInteger(valueBytes);
|
value = new BigInteger(1, valueBytes);
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -783,7 +784,7 @@ public class RLP {
|
||||||
if(srcBigInteger == BigInteger.ZERO)
|
if(srcBigInteger == BigInteger.ZERO)
|
||||||
return encodeByte((byte)0);
|
return encodeByte((byte)0);
|
||||||
else
|
else
|
||||||
return encodeElement(srcBigInteger.toByteArray());
|
return encodeElement(asUnsignedByteArray(srcBigInteger));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static byte[] encodeElement(byte[] srcData) {
|
public static byte[] encodeElement(byte[] srcData) {
|
||||||
|
@ -878,13 +879,13 @@ public class RLP {
|
||||||
return inputString.getBytes();
|
return inputString.getBytes();
|
||||||
} else if(input instanceof Long) {
|
} else if(input instanceof Long) {
|
||||||
Long inputLong = (Long) input;
|
Long inputLong = (Long) input;
|
||||||
return (inputLong == 0) ? new byte[0] : BigInteger.valueOf(inputLong).toByteArray();
|
return (inputLong == 0) ? new byte[0] : asUnsignedByteArray(BigInteger.valueOf(inputLong));
|
||||||
} else if(input instanceof Integer) {
|
} else if(input instanceof Integer) {
|
||||||
Integer inputInt = (Integer) input;
|
Integer inputInt = (Integer) input;
|
||||||
return (inputInt == 0) ? new byte[0] : BigInteger.valueOf(inputInt.longValue()).toByteArray();
|
return (inputInt == 0) ? new byte[0] : asUnsignedByteArray(BigInteger.valueOf(inputInt.intValue()));
|
||||||
} else if(input instanceof BigInteger) {
|
} else if(input instanceof BigInteger) {
|
||||||
BigInteger inputBigInt = (BigInteger) input;
|
BigInteger inputBigInt = (BigInteger) input;
|
||||||
return (inputBigInt == BigInteger.ZERO) ? new byte[0] : inputBigInt.toByteArray();
|
return (inputBigInt == BigInteger.ZERO) ? new byte[0] : asUnsignedByteArray(inputBigInt);
|
||||||
} else if (input instanceof Value) {
|
} else if (input instanceof Value) {
|
||||||
Value val = (Value) input;
|
Value val = (Value) input;
|
||||||
return toBytes(val.asObj());
|
return toBytes(val.asObj());
|
||||||
|
|
|
@ -44,7 +44,7 @@ public class Value {
|
||||||
if (isInt()) {
|
if (isInt()) {
|
||||||
return (Integer) value;
|
return (Integer) value;
|
||||||
} else if (isBytes()) {
|
} else if (isBytes()) {
|
||||||
return new BigInteger(asBytes()).intValue();
|
return new BigInteger(1, asBytes()).intValue();
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -53,7 +53,7 @@ public class Value {
|
||||||
if (isLong()) {
|
if (isLong()) {
|
||||||
return (Long) value;
|
return (Long) value;
|
||||||
} else if (isBytes()) {
|
} else if (isBytes()) {
|
||||||
return new BigInteger(asBytes()).longValue();
|
return new BigInteger(1, asBytes()).longValue();
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,15 +1,36 @@
|
||||||
|
|
||||||
|
|
||||||
# if the system will work as a server also
|
# if the system will work as a server also
|
||||||
# accept for incoming connections [true/false]
|
# accept for incoming connections [true/false]
|
||||||
server.acceptConnections = false
|
server.acceptConnections = false
|
||||||
|
|
||||||
|
|
||||||
# one default access point to start
|
# one default access point to start
|
||||||
# discover the network e.g. ip: [54.201.28.117] port: [30303]
|
# discover the network e.g. ip: [54.201.28.117] port: [30303]
|
||||||
peer.discovery.ip = 54.201.28.117
|
peer.discovery.ip = 54.201.28.117
|
||||||
peer.discovery.port = 30303
|
peer.discovery.port = 30303
|
||||||
|
|
||||||
|
# Peer Server Zero: peer discovery
|
||||||
|
#peer.discovery.ip = 54.201.28.117
|
||||||
|
#peer.discovery.port = 30303
|
||||||
|
|
||||||
|
# Peer Server One: peer discovery
|
||||||
|
#peer.discovery.ip = 54.204.10.41
|
||||||
|
#peer.discovery.port = 30303
|
||||||
|
|
||||||
|
# Some dude in Canada
|
||||||
|
#peer.discovery.ip = 131.104.247.135
|
||||||
|
#peer.discovery.port = 30303
|
||||||
|
|
||||||
|
# Nick
|
||||||
|
#peer.discovery.ip = 82.217.72.169
|
||||||
|
#peer.discovery.port = 30303
|
||||||
|
|
||||||
|
# ZeroGox
|
||||||
|
#peer.discovery.ip = 54.204.10.41
|
||||||
|
#peer.discovery.port = 30303
|
||||||
|
|
||||||
|
# RomanJ
|
||||||
|
# peer.discovery.ip = 54.211.14.10
|
||||||
|
# peer.discovery.port = 40404
|
||||||
|
|
||||||
|
|
||||||
# active peer ip and port
|
# active peer ip and port
|
||||||
# that is the peer through
|
# that is the peer through
|
||||||
|
@ -44,8 +65,13 @@ peer.discovery.timeout = 2
|
||||||
# retrieved from the peer [seconds]
|
# retrieved from the peer [seconds]
|
||||||
transaction.approve.timeout = 5
|
transaction.approve.timeout = 5
|
||||||
|
|
||||||
|
|
||||||
# default directory where we keep
|
# default directory where we keep
|
||||||
# basic Serpent samples relative
|
# basic Serpent samples relative
|
||||||
# to home.dir
|
# to home.dir
|
||||||
samples.dir = samples
|
samples.dir = samples
|
||||||
|
|
||||||
|
# everytime the application starts
|
||||||
|
# the existing database will be
|
||||||
|
# destroyed and all the data will be
|
||||||
|
# downloaded from peers again
|
||||||
|
database.reset = true
|
||||||
|
|
|
@ -0,0 +1,19 @@
|
||||||
|
package org.ethereum.core;
|
||||||
|
|
||||||
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
|
import java.math.BigInteger;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.spongycastle.util.encoders.Hex;
|
||||||
|
|
||||||
|
public class AccountStateTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetEncoded() {
|
||||||
|
String expected = "f83e9a01000000000000000000000000000000000000000000000000008080a0c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470";
|
||||||
|
AccountState acct = new AccountState(BigInteger.ZERO, BigInteger.valueOf(2).pow(200));
|
||||||
|
assertEquals(expected, Hex.toHexString(acct.getEncoded()));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,53 @@
|
||||||
|
package org.ethereum.core;
|
||||||
|
|
||||||
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
|
import java.math.BigInteger;
|
||||||
|
|
||||||
|
import org.ethereum.trie.MockDB;
|
||||||
|
import org.ethereum.trie.Trie;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.spongycastle.util.encoders.Hex;
|
||||||
|
|
||||||
|
public class StateTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGenesisAccounts() {
|
||||||
|
Trie trie = new Trie(new MockDB());
|
||||||
|
|
||||||
|
// 2ef47100e0787b915105fd5e3f4ff6752079d5cb # (M)
|
||||||
|
AccountState acct5 = new AccountState(BigInteger.ZERO, BigInteger.valueOf(2).pow(200));
|
||||||
|
trie.update(Hex.decode("2ef47100e0787b915105fd5e3f4ff6752079d5cb"), acct5.getEncoded());
|
||||||
|
|
||||||
|
// 1a26338f0d905e295fccb71fa9ea849ffa12aaf4 # (A)
|
||||||
|
AccountState acct4 = new AccountState(BigInteger.ZERO, BigInteger.valueOf(2).pow(200));
|
||||||
|
trie.update(Hex.decode("1a26338f0d905e295fccb71fa9ea849ffa12aaf4"), acct4.getEncoded());
|
||||||
|
|
||||||
|
// e6716f9544a56c530d868e4bfbacb172315bdead # (J)
|
||||||
|
AccountState acct2 = new AccountState(BigInteger.ZERO, BigInteger.valueOf(2).pow(200));
|
||||||
|
trie.update(Hex.decode("e6716f9544a56c530d868e4bfbacb172315bdead"), acct2.getEncoded());
|
||||||
|
|
||||||
|
// 8a40bfaa73256b60764c1bf40675a99083efb075 # (G)
|
||||||
|
AccountState acct1 = new AccountState(BigInteger.ZERO, BigInteger.valueOf(2).pow(200));
|
||||||
|
trie.update(Hex.decode("8a40bfaa73256b60764c1bf40675a99083efb075"), acct1.getEncoded());
|
||||||
|
|
||||||
|
// e4157b34ea9615cfbde6b4fda419828124b70c78 # (CH)
|
||||||
|
AccountState acct8 = new AccountState(BigInteger.ZERO, BigInteger.valueOf(2).pow(200));
|
||||||
|
trie.update(Hex.decode("e4157b34ea9615cfbde6b4fda419828124b70c78"), acct8.getEncoded());
|
||||||
|
|
||||||
|
// 1e12515ce3e0f817a4ddef9ca55788a1d66bd2df # (V)
|
||||||
|
AccountState acct3 = new AccountState(BigInteger.ZERO, BigInteger.valueOf(2).pow(200));
|
||||||
|
trie.update(Hex.decode("1e12515ce3e0f817a4ddef9ca55788a1d66bd2df"), acct3.getEncoded());
|
||||||
|
|
||||||
|
// 6c386a4b26f73c802f34673f7248bb118f97424a # (HH)
|
||||||
|
AccountState acct7 = new AccountState(BigInteger.ZERO, BigInteger.valueOf(2).pow(200));
|
||||||
|
trie.update(Hex.decode("6c386a4b26f73c802f34673f7248bb118f97424a"), acct7.getEncoded());
|
||||||
|
|
||||||
|
// cd2a3d9f938e13cd947ec05abc7fe734df8dd826 # (R)
|
||||||
|
AccountState acct6 = new AccountState(BigInteger.ZERO, BigInteger.valueOf(2).pow(200));
|
||||||
|
trie.update(Hex.decode("cd2a3d9f938e13cd947ec05abc7fe734df8dd826"), acct6.getEncoded());
|
||||||
|
|
||||||
|
assertEquals("12582945fc5ad12c3e7b67c4fc37a68fc0d52d995bb7f7291ff41a2739a7ca16", Hex.toHexString(trie.getRootHash()));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1,6 +1,7 @@
|
||||||
package org.ethereum.core;
|
package org.ethereum.core;
|
||||||
|
|
||||||
import static org.junit.Assert.*;
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertNull;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.math.BigInteger;
|
import java.math.BigInteger;
|
||||||
|
@ -148,7 +149,6 @@ public class TransactionTest {
|
||||||
assertEquals(Hex.toHexString(testReceiveAddress), Hex.toHexString(txSigned.getReceiveAddress()));
|
assertEquals(Hex.toHexString(testReceiveAddress), Hex.toHexString(txSigned.getReceiveAddress()));
|
||||||
assertEquals(new BigInteger(1, testValue), new BigInteger(1, txSigned.getValue()));
|
assertEquals(new BigInteger(1, testValue), new BigInteger(1, txSigned.getValue()));
|
||||||
assertNull(txSigned.getData());
|
assertNull(txSigned.getData());
|
||||||
assertNull(txSigned.getInit());
|
|
||||||
assertEquals(27, txSigned.getSignature().v);
|
assertEquals(27, txSigned.getSignature().v);
|
||||||
assertEquals("eab47c1a49bf2fe5d40e01d313900e19ca485867d462fe06e139e3a536c6d4f4", Hex.toHexString(BigIntegers.asUnsignedByteArray(txSigned.getSignature().r)));
|
assertEquals("eab47c1a49bf2fe5d40e01d313900e19ca485867d462fe06e139e3a536c6d4f4", Hex.toHexString(BigIntegers.asUnsignedByteArray(txSigned.getSignature().r)));
|
||||||
assertEquals("14a569d327dcda4b29f74f93c0e9729d2f49ad726e703f9cd90dbb0fbf6649f1", Hex.toHexString(BigIntegers.asUnsignedByteArray(txSigned.getSignature().s)));
|
assertEquals("14a569d327dcda4b29f74f93c0e9729d2f49ad726e703f9cd90dbb0fbf6649f1", Hex.toHexString(BigIntegers.asUnsignedByteArray(txSigned.getSignature().s)));
|
||||||
|
@ -169,7 +169,6 @@ public class TransactionTest {
|
||||||
assertEquals(Hex.toHexString(testReceiveAddress), Hex.toHexString(txUnsigned.getReceiveAddress()));
|
assertEquals(Hex.toHexString(testReceiveAddress), Hex.toHexString(txUnsigned.getReceiveAddress()));
|
||||||
assertEquals(new BigInteger(1, testValue), new BigInteger(1, txUnsigned.getValue()));
|
assertEquals(new BigInteger(1, testValue), new BigInteger(1, txUnsigned.getValue()));
|
||||||
assertNull(txUnsigned.getData());
|
assertNull(txUnsigned.getData());
|
||||||
assertNull(txUnsigned.getInit());
|
|
||||||
assertEquals(27, txUnsigned.getSignature().v);
|
assertEquals(27, txUnsigned.getSignature().v);
|
||||||
assertEquals("eab47c1a49bf2fe5d40e01d313900e19ca485867d462fe06e139e3a536c6d4f4", Hex.toHexString(BigIntegers.asUnsignedByteArray(txUnsigned.getSignature().r)));
|
assertEquals("eab47c1a49bf2fe5d40e01d313900e19ca485867d462fe06e139e3a536c6d4f4", Hex.toHexString(BigIntegers.asUnsignedByteArray(txUnsigned.getSignature().r)));
|
||||||
assertEquals("14a569d327dcda4b29f74f93c0e9729d2f49ad726e703f9cd90dbb0fbf6649f1", Hex.toHexString(BigIntegers.asUnsignedByteArray(txUnsigned.getSignature().s)));
|
assertEquals("14a569d327dcda4b29f74f93c0e9729d2f49ad726e703f9cd90dbb0fbf6649f1", Hex.toHexString(BigIntegers.asUnsignedByteArray(txUnsigned.getSignature().s)));
|
||||||
|
@ -185,7 +184,6 @@ public class TransactionTest {
|
||||||
assertEquals(Hex.toHexString(testReceiveAddress), Hex.toHexString(txNew.getReceiveAddress()));
|
assertEquals(Hex.toHexString(testReceiveAddress), Hex.toHexString(txNew.getReceiveAddress()));
|
||||||
assertEquals(new BigInteger(1, testValue), new BigInteger(1, txNew.getValue()));
|
assertEquals(new BigInteger(1, testValue), new BigInteger(1, txNew.getValue()));
|
||||||
assertEquals("", Hex.toHexString(txNew.getData()));
|
assertEquals("", Hex.toHexString(txNew.getData()));
|
||||||
assertNull(txNew.getInit());
|
|
||||||
assertNull(txNew.getSignature());
|
assertNull(txNew.getSignature());
|
||||||
|
|
||||||
assertEquals(RLP_ENCODED_RAW_TX, Hex.toHexString(txNew.getEncodedRaw()));
|
assertEquals(RLP_ENCODED_RAW_TX, Hex.toHexString(txNew.getEncodedRaw()));
|
||||||
|
@ -228,7 +226,6 @@ public class TransactionTest {
|
||||||
assertEquals(HASH_TX_UNSIGNED, Hex.toHexString(tx.getHash()));
|
assertEquals(HASH_TX_UNSIGNED, Hex.toHexString(tx.getHash()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testTransactionCreateContract(){
|
public void testTransactionCreateContract(){
|
||||||
|
|
||||||
|
@ -266,8 +263,6 @@ public class TransactionTest {
|
||||||
System.out.println("plainTx1: " + plainTx1 );
|
System.out.println("plainTx1: " + plainTx1 );
|
||||||
System.out.println("plainTx2: " + plainTx2 );
|
System.out.println("plainTx2: " + plainTx2 );
|
||||||
|
|
||||||
|
|
||||||
System.out.println( Hex.toHexString( tx2.getSender() ));
|
System.out.println( Hex.toHexString( tx2.getSender() ));
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,8 +29,8 @@ public class WalletTest {
|
||||||
wallet.importKey(catKey.getPrivKeyBytes());
|
wallet.importKey(catKey.getPrivKeyBytes());
|
||||||
|
|
||||||
|
|
||||||
AddressState cowAddressState = (AddressState) wallet.getAddressState(cowKey.getAddress());
|
AccountState cowAddressState = (AccountState) wallet.getAddressState(cowKey.getAddress());
|
||||||
AddressState catAddressState = (AddressState) wallet.getAddressState(catKey.getAddress());
|
AccountState catAddressState = (AccountState) wallet.getAddressState(catKey.getAddress());
|
||||||
|
|
||||||
cowAddressState.addToBalance(new BigInteger("234234"));
|
cowAddressState.addToBalance(new BigInteger("234234"));
|
||||||
catAddressState.addToBalance(new BigInteger("84758"));
|
catAddressState.addToBalance(new BigInteger("84758"));
|
||||||
|
|
|
@ -90,7 +90,7 @@ public class CryptoTest {
|
||||||
// todo: https://tools.ietf.org/html/rfc6979#section-2.2
|
// todo: https://tools.ietf.org/html/rfc6979#section-2.2
|
||||||
// todo: https://github.com/bcgit/bc-java/blob/master/core/src/main/java/org/bouncycastle/crypto/signers/ECDSASigner.java
|
// todo: https://github.com/bcgit/bc-java/blob/master/core/src/main/java/org/bouncycastle/crypto/signers/ECDSASigner.java
|
||||||
|
|
||||||
System.out.println(new BigInteger(1, Hex.decode("3913517ebd3c0c65000000")));
|
System.out.println(new BigInteger(Hex.decode("3913517ebd3c0c65000000")));
|
||||||
|
|
||||||
System.out.println(Utils.getValueShortString(new BigInteger("69000000000000000000000000")));
|
System.out.println(Utils.getValueShortString(new BigInteger("69000000000000000000000000")));
|
||||||
|
|
||||||
|
|
|
@ -202,7 +202,7 @@ public class MessagesTest {
|
||||||
assertEquals("64", Hex.toHexString(tx.getGasPrice()));
|
assertEquals("64", Hex.toHexString(tx.getGasPrice()));
|
||||||
assertEquals("09184e72a000", Hex.toHexString(tx.getGasLimit()));
|
assertEquals("09184e72a000", Hex.toHexString(tx.getGasLimit()));
|
||||||
assertEquals("null", ByteUtil.toHexString(tx.getData()));
|
assertEquals("null", ByteUtil.toHexString(tx.getData()));
|
||||||
assertEquals("null", ByteUtil.toHexString(tx.getInit()));
|
|
||||||
assertEquals("1b", Hex.toHexString(new byte[] { tx.getSignature().v }));
|
assertEquals("1b", Hex.toHexString(new byte[] { tx.getSignature().v }));
|
||||||
assertEquals("5c89ebf2b77eeab88251e553f6f9d53badc1d800bbac02d830801c2aa94a4c9f", Hex.toHexString(tx.getSignature().r.toByteArray()));
|
assertEquals("5c89ebf2b77eeab88251e553f6f9d53badc1d800bbac02d830801c2aa94a4c9f", Hex.toHexString(tx.getSignature().r.toByteArray()));
|
||||||
assertEquals("0b7907532b1f29c79942b75fff98822293bf5fdaa3653a8d9f424c6a3265f06c", Hex.toHexString(tx.getSignature().s.toByteArray()));
|
assertEquals("0b7907532b1f29c79942b75fff98822293bf5fdaa3653a8d9f424c6a3265f06c", Hex.toHexString(tx.getSignature().s.toByteArray()));
|
||||||
|
@ -263,9 +263,6 @@ public class MessagesTest {
|
||||||
assertEquals("606956330c0d630000003359366000530a0d630000003359602060005301356000533557604060005301600054630000000c58",
|
assertEquals("606956330c0d630000003359366000530a0d630000003359602060005301356000533557604060005301600054630000000c58",
|
||||||
Hex.toHexString( tx.getData() ));
|
Hex.toHexString( tx.getData() ));
|
||||||
|
|
||||||
assertEquals("33606957",
|
|
||||||
Hex.toHexString( tx.getInit() ));
|
|
||||||
|
|
||||||
assertEquals("1c",
|
assertEquals("1c",
|
||||||
Hex.toHexString( new byte[] {tx.getSignature().v} ));
|
Hex.toHexString( new byte[] {tx.getSignature().v} ));
|
||||||
|
|
||||||
|
@ -298,9 +295,6 @@ public class MessagesTest {
|
||||||
assertEquals("00000000000000000000000000000000000000000000000000000000000000000000000000000000000000002d0aceee7e5ab874e22ccf8d1a649f59106d74e8",
|
assertEquals("00000000000000000000000000000000000000000000000000000000000000000000000000000000000000002d0aceee7e5ab874e22ccf8d1a649f59106d74e8",
|
||||||
Hex.toHexString( tx.getData() ));
|
Hex.toHexString( tx.getData() ));
|
||||||
|
|
||||||
assertEquals("null",
|
|
||||||
Hex.toHexString( tx.getInit() ));
|
|
||||||
|
|
||||||
assertEquals("1b",
|
assertEquals("1b",
|
||||||
Hex.toHexString( new byte[] {tx.getSignature().v} ));
|
Hex.toHexString( new byte[] {tx.getSignature().v} ));
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,7 @@ import static org.junit.Assert.*;
|
||||||
|
|
||||||
import org.ethereum.trie.Trie;
|
import org.ethereum.trie.Trie;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
import org.spongycastle.util.encoders.Hex;
|
||||||
|
|
||||||
public class TrieTest {
|
public class TrieTest {
|
||||||
|
|
||||||
|
@ -34,7 +35,7 @@ public class TrieTest {
|
||||||
Trie trie = new Trie(mockDb);
|
Trie trie = new Trie(mockDb);
|
||||||
|
|
||||||
trie.update("", dog);
|
trie.update("", dog);
|
||||||
assertEquals(dog, trie.get(""));
|
assertEquals(dog, new String(trie.get("")));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -42,7 +43,7 @@ public class TrieTest {
|
||||||
Trie trie = new Trie(mockDb);
|
Trie trie = new Trie(mockDb);
|
||||||
|
|
||||||
trie.update(cat, dog);
|
trie.update(cat, dog);
|
||||||
assertEquals(dog, trie.get(cat));
|
assertEquals(dog, new String(trie.get(cat)));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -50,33 +51,33 @@ public class TrieTest {
|
||||||
Trie trie = new Trie(mockDb);
|
Trie trie = new Trie(mockDb);
|
||||||
|
|
||||||
trie.update(cat, LONG_STRING);
|
trie.update(cat, LONG_STRING);
|
||||||
assertEquals(LONG_STRING, trie.get(cat));
|
assertEquals(LONG_STRING, new String(trie.get(cat)));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testInsertMultipleItems1() {
|
public void testInsertMultipleItems1() {
|
||||||
Trie trie = new Trie(mockDb);
|
Trie trie = new Trie(mockDb);
|
||||||
trie.update(ca, dude);
|
trie.update(ca, dude);
|
||||||
assertEquals(dude, trie.get(ca));
|
assertEquals(dude, new String(trie.get(ca)));
|
||||||
|
|
||||||
trie.update(cat, dog);
|
trie.update(cat, dog);
|
||||||
assertEquals(dog, trie.get(cat));
|
assertEquals(dog, new String(trie.get(cat)));
|
||||||
|
|
||||||
trie.update(dog, test);
|
trie.update(dog, test);
|
||||||
assertEquals(test, trie.get(dog));
|
assertEquals(test, new String(trie.get(dog)));
|
||||||
|
|
||||||
trie.update(doge, LONG_STRING);
|
trie.update(doge, LONG_STRING);
|
||||||
assertEquals(LONG_STRING, trie.get(doge));
|
assertEquals(LONG_STRING, new String(trie.get(doge)));
|
||||||
|
|
||||||
trie.update(test, LONG_STRING);
|
trie.update(test, LONG_STRING);
|
||||||
assertEquals(LONG_STRING, trie.get(test));
|
assertEquals(LONG_STRING, new String(trie.get(test)));
|
||||||
|
|
||||||
// Test if everything is still there
|
// Test if everything is still there
|
||||||
assertEquals(dude, trie.get(ca));
|
assertEquals(dude, new String(trie.get(ca)));
|
||||||
assertEquals(dog, trie.get(cat));
|
assertEquals(dog, new String(trie.get(cat)));
|
||||||
assertEquals(test, trie.get(dog));
|
assertEquals(test, new String(trie.get(dog)));
|
||||||
assertEquals(LONG_STRING, trie.get(doge));
|
assertEquals(LONG_STRING, new String(trie.get(doge)));
|
||||||
assertEquals(LONG_STRING, trie.get(test));
|
assertEquals(LONG_STRING, new String(trie.get(test)));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -84,26 +85,26 @@ public class TrieTest {
|
||||||
Trie trie = new Trie(mockDb);
|
Trie trie = new Trie(mockDb);
|
||||||
|
|
||||||
trie.update(cat, dog);
|
trie.update(cat, dog);
|
||||||
assertEquals(dog, trie.get(cat));
|
assertEquals(dog, new String(trie.get(cat)));
|
||||||
|
|
||||||
trie.update(ca, dude);
|
trie.update(ca, dude);
|
||||||
assertEquals(dude, trie.get(ca));
|
assertEquals(dude, new String(trie.get(ca)));
|
||||||
|
|
||||||
trie.update(doge, LONG_STRING);
|
trie.update(doge, LONG_STRING);
|
||||||
assertEquals(LONG_STRING, trie.get(doge));
|
assertEquals(LONG_STRING, new String(trie.get(doge)));
|
||||||
|
|
||||||
trie.update(dog, test);
|
trie.update(dog, test);
|
||||||
assertEquals(test, trie.get(dog));
|
assertEquals(test, new String(trie.get(dog)));
|
||||||
|
|
||||||
trie.update(test, LONG_STRING);
|
trie.update(test, LONG_STRING);
|
||||||
assertEquals(LONG_STRING, trie.get(test));
|
assertEquals(LONG_STRING, new String(trie.get(test)));
|
||||||
|
|
||||||
// Test if everything is still there
|
// Test if everything is still there
|
||||||
assertEquals(dog, trie.get(cat));
|
assertEquals(dog, new String(trie.get(cat)));
|
||||||
assertEquals(dude, trie.get(ca));
|
assertEquals(dude, new String(trie.get(ca)));
|
||||||
assertEquals(LONG_STRING, trie.get(doge));
|
assertEquals(LONG_STRING, new String(trie.get(doge)));
|
||||||
assertEquals(test, trie.get(dog));
|
assertEquals(test, new String(trie.get(dog)));
|
||||||
assertEquals(LONG_STRING, trie.get(test));
|
assertEquals(LONG_STRING, new String(trie.get(test)));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -111,19 +112,19 @@ public class TrieTest {
|
||||||
Trie trie = new Trie(mockDb);
|
Trie trie = new Trie(mockDb);
|
||||||
|
|
||||||
trie.update(cat, dog);
|
trie.update(cat, dog);
|
||||||
assertEquals(dog, trie.get(cat));
|
assertEquals(dog, new String(trie.get(cat)));
|
||||||
|
|
||||||
trie.update(cat, dog+"1");
|
trie.update(cat, dog+"1");
|
||||||
assertEquals(dog+"1", trie.get(cat));
|
assertEquals(dog+"1", new String(trie.get(cat)));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testUpdateLongToLongString() {
|
public void testUpdateLongToLongString() {
|
||||||
Trie trie = new Trie(mockDb);
|
Trie trie = new Trie(mockDb);
|
||||||
trie.update(cat, LONG_STRING);
|
trie.update(cat, LONG_STRING);
|
||||||
assertEquals(LONG_STRING, trie.get(cat));
|
assertEquals(LONG_STRING, new String(trie.get(cat)));
|
||||||
trie.update(cat, LONG_STRING+"1");
|
trie.update(cat, LONG_STRING+"1");
|
||||||
assertEquals(LONG_STRING+"1", trie.get(cat));
|
assertEquals(LONG_STRING+"1", new String(trie.get(cat)));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -131,10 +132,10 @@ public class TrieTest {
|
||||||
Trie trie = new Trie(mockDb);
|
Trie trie = new Trie(mockDb);
|
||||||
|
|
||||||
trie.update(cat, dog);
|
trie.update(cat, dog);
|
||||||
assertEquals(dog, trie.get(cat));
|
assertEquals(dog, new String(trie.get(cat)));
|
||||||
|
|
||||||
trie.update(cat, LONG_STRING+"1");
|
trie.update(cat, LONG_STRING+"1");
|
||||||
assertEquals(LONG_STRING+"1", trie.get(cat));
|
assertEquals(LONG_STRING+"1", new String(trie.get(cat)));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -142,10 +143,10 @@ public class TrieTest {
|
||||||
Trie trie = new Trie(mockDb);
|
Trie trie = new Trie(mockDb);
|
||||||
|
|
||||||
trie.update(cat, LONG_STRING);
|
trie.update(cat, LONG_STRING);
|
||||||
assertEquals(LONG_STRING, trie.get(cat));
|
assertEquals(LONG_STRING, new String(trie.get(cat)));
|
||||||
|
|
||||||
trie.update(cat, dog+"1");
|
trie.update(cat, dog+"1");
|
||||||
assertEquals(dog+"1", trie.get(cat));
|
assertEquals(dog+"1", new String(trie.get(cat)));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -155,15 +156,15 @@ public class TrieTest {
|
||||||
Trie trie = new Trie(mockDb);
|
Trie trie = new Trie(mockDb);
|
||||||
|
|
||||||
trie.update(cat, dog);
|
trie.update(cat, dog);
|
||||||
assertEquals(dog, trie.get(cat));
|
assertEquals(dog, new String(trie.get(cat)));
|
||||||
|
|
||||||
trie.update(ca, dude);
|
trie.update(ca, dude);
|
||||||
assertEquals(dude, trie.get(ca));
|
assertEquals(dude, new String(trie.get(ca)));
|
||||||
assertEquals(ROOT_HASH_BEFORE, trie.getRootHash());
|
assertEquals(ROOT_HASH_BEFORE, Hex.toHexString(trie.getRootHash()));
|
||||||
|
|
||||||
trie.delete(ca);
|
trie.delete(ca);
|
||||||
assertEquals("", trie.get(ca));
|
assertEquals("", new String(trie.get(ca)));
|
||||||
assertEquals(ROOT_HASH_AFTER, trie.getRootHash());
|
assertEquals(ROOT_HASH_AFTER, Hex.toHexString(trie.getRootHash()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -173,15 +174,15 @@ public class TrieTest {
|
||||||
Trie trie = new Trie(mockDb);
|
Trie trie = new Trie(mockDb);
|
||||||
|
|
||||||
trie.update(ca, dude);
|
trie.update(ca, dude);
|
||||||
assertEquals(dude, trie.get(ca));
|
assertEquals(dude, new String(trie.get(ca)));
|
||||||
|
|
||||||
trie.update(cat, dog);
|
trie.update(cat, dog);
|
||||||
assertEquals(dog, trie.get(cat));
|
assertEquals(dog, new String(trie.get(cat)));
|
||||||
assertEquals(ROOT_HASH_BEFORE, trie.getRootHash());
|
assertEquals(ROOT_HASH_BEFORE, Hex.toHexString(trie.getRootHash()));
|
||||||
|
|
||||||
trie.delete(cat);
|
trie.delete(cat);
|
||||||
assertEquals("", trie.get(cat));
|
assertEquals("", new String(trie.get(cat)));
|
||||||
assertEquals(ROOT_HASH_AFTER, trie.getRootHash());
|
assertEquals(ROOT_HASH_AFTER, Hex.toHexString(trie.getRootHash()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -191,15 +192,15 @@ public class TrieTest {
|
||||||
Trie trie = new Trie(mockDb);
|
Trie trie = new Trie(mockDb);
|
||||||
|
|
||||||
trie.update(cat, dude);
|
trie.update(cat, dude);
|
||||||
assertEquals(dude, trie.get(cat));
|
assertEquals(dude, new String(trie.get(cat)));
|
||||||
|
|
||||||
trie.update(dog, test);
|
trie.update(dog, test);
|
||||||
assertEquals(test, trie.get(dog));
|
assertEquals(test, new String(trie.get(dog)));
|
||||||
assertEquals(ROOT_HASH_BEFORE, trie.getRootHash());
|
assertEquals(ROOT_HASH_BEFORE, Hex.toHexString(trie.getRootHash()));
|
||||||
|
|
||||||
trie.delete(dog);
|
trie.delete(dog);
|
||||||
assertEquals("", trie.get(dog));
|
assertEquals("", new String(trie.get(dog)));
|
||||||
assertEquals(ROOT_HASH_AFTER, trie.getRootHash());
|
assertEquals(ROOT_HASH_AFTER, Hex.toHexString(trie.getRootHash()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -209,15 +210,15 @@ public class TrieTest {
|
||||||
Trie trie = new Trie(mockDb);
|
Trie trie = new Trie(mockDb);
|
||||||
|
|
||||||
trie.update(cat, LONG_STRING);
|
trie.update(cat, LONG_STRING);
|
||||||
assertEquals(LONG_STRING, trie.get(cat));
|
assertEquals(LONG_STRING, new String(trie.get(cat)));
|
||||||
|
|
||||||
trie.update(dog, LONG_STRING);
|
trie.update(dog, LONG_STRING);
|
||||||
assertEquals(LONG_STRING, trie.get(dog));
|
assertEquals(LONG_STRING, new String(trie.get(dog)));
|
||||||
assertEquals(ROOT_HASH_BEFORE, trie.getRootHash());
|
assertEquals(ROOT_HASH_BEFORE, Hex.toHexString(trie.getRootHash()));
|
||||||
|
|
||||||
trie.delete(dog);
|
trie.delete(dog);
|
||||||
assertEquals("", trie.get(dog));
|
assertEquals("", new String(trie.get(dog)));
|
||||||
assertEquals(ROOT_HASH_AFTER, trie.getRootHash());
|
assertEquals(ROOT_HASH_AFTER, Hex.toHexString(trie.getRootHash()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -227,15 +228,15 @@ public class TrieTest {
|
||||||
Trie trie = new Trie(mockDb);
|
Trie trie = new Trie(mockDb);
|
||||||
|
|
||||||
trie.update(ca, LONG_STRING);
|
trie.update(ca, LONG_STRING);
|
||||||
assertEquals(LONG_STRING, trie.get(ca));
|
assertEquals(LONG_STRING, new String(trie.get(ca)));
|
||||||
|
|
||||||
trie.update(cat, LONG_STRING);
|
trie.update(cat, LONG_STRING);
|
||||||
assertEquals(LONG_STRING, trie.get(cat));
|
assertEquals(LONG_STRING, new String(trie.get(cat)));
|
||||||
assertEquals(ROOT_HASH_BEFORE, trie.getRootHash());
|
assertEquals(ROOT_HASH_BEFORE, Hex.toHexString(trie.getRootHash()));
|
||||||
|
|
||||||
trie.delete(cat);
|
trie.delete(cat);
|
||||||
assertEquals("", trie.get(cat));
|
assertEquals("", new String(trie.get(cat)));
|
||||||
assertEquals(ROOT_HASH_AFTER, trie.getRootHash());
|
assertEquals(ROOT_HASH_AFTER, Hex.toHexString(trie.getRootHash()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -245,15 +246,15 @@ public class TrieTest {
|
||||||
Trie trie = new Trie(mockDb);
|
Trie trie = new Trie(mockDb);
|
||||||
|
|
||||||
trie.update(cat, LONG_STRING);
|
trie.update(cat, LONG_STRING);
|
||||||
assertEquals(LONG_STRING, trie.get(cat));
|
assertEquals(LONG_STRING, new String(trie.get(cat)));
|
||||||
|
|
||||||
trie.update(ca, LONG_STRING);
|
trie.update(ca, LONG_STRING);
|
||||||
assertEquals(LONG_STRING, trie.get(ca));
|
assertEquals(LONG_STRING, new String(trie.get(ca)));
|
||||||
assertEquals(ROOT_HASH_BEFORE, trie.getRootHash());
|
assertEquals(ROOT_HASH_BEFORE, Hex.toHexString(trie.getRootHash()));
|
||||||
|
|
||||||
trie.delete(ca);
|
trie.delete(ca);
|
||||||
assertEquals("", trie.get(ca));
|
assertEquals("", new String(trie.get(ca)));
|
||||||
assertEquals(ROOT_HASH_AFTER, trie.getRootHash());
|
assertEquals(ROOT_HASH_AFTER, Hex.toHexString(trie.getRootHash()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -264,28 +265,28 @@ public class TrieTest {
|
||||||
Trie trie = new Trie(mockDb);
|
Trie trie = new Trie(mockDb);
|
||||||
|
|
||||||
trie.update(cat, dog);
|
trie.update(cat, dog);
|
||||||
assertEquals(dog, trie.get(cat));
|
assertEquals(dog, new String(trie.get(cat)));
|
||||||
|
|
||||||
trie.update(ca, dude);
|
trie.update(ca, dude);
|
||||||
assertEquals(dude, trie.get(ca));
|
assertEquals(dude, new String(trie.get(ca)));
|
||||||
|
|
||||||
trie.update(doge, LONG_STRING);
|
trie.update(doge, LONG_STRING);
|
||||||
assertEquals(LONG_STRING, trie.get(doge));
|
assertEquals(LONG_STRING, new String(trie.get(doge)));
|
||||||
|
|
||||||
trie.update(dog, test);
|
trie.update(dog, test);
|
||||||
assertEquals(test, trie.get(dog));
|
assertEquals(test, new String(trie.get(dog)));
|
||||||
|
|
||||||
trie.update(test, LONG_STRING);
|
trie.update(test, LONG_STRING);
|
||||||
assertEquals(LONG_STRING, trie.get(test));
|
assertEquals(LONG_STRING, new String(trie.get(test)));
|
||||||
assertEquals(ROOT_HASH_BEFORE, trie.getRootHash());
|
assertEquals(ROOT_HASH_BEFORE, Hex.toHexString(trie.getRootHash()));
|
||||||
|
|
||||||
trie.delete(dog);
|
trie.delete(dog);
|
||||||
assertEquals("", trie.get(dog));
|
assertEquals("", new String(trie.get(dog)));
|
||||||
assertEquals(ROOT_HASH_AFTER1, trie.getRootHash());
|
assertEquals(ROOT_HASH_AFTER1, Hex.toHexString(trie.getRootHash()));
|
||||||
|
|
||||||
trie.delete(test);
|
trie.delete(test);
|
||||||
assertEquals("", trie.get(test));
|
assertEquals("", new String(trie.get(test)));
|
||||||
assertEquals(ROOT_HASH_AFTER2, trie.getRootHash());
|
assertEquals(ROOT_HASH_AFTER2, Hex.toHexString(trie.getRootHash()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -296,39 +297,39 @@ public class TrieTest {
|
||||||
|
|
||||||
Trie trie = new Trie(mockDb);
|
Trie trie = new Trie(mockDb);
|
||||||
trie.update(c, LONG_STRING);
|
trie.update(c, LONG_STRING);
|
||||||
assertEquals(LONG_STRING, trie.get(c));
|
assertEquals(LONG_STRING, new String(trie.get(c)));
|
||||||
|
|
||||||
trie.update(ca, LONG_STRING);
|
trie.update(ca, LONG_STRING);
|
||||||
assertEquals(LONG_STRING, trie.get(ca));
|
assertEquals(LONG_STRING, new String(trie.get(ca)));
|
||||||
|
|
||||||
trie.update(cat, LONG_STRING);
|
trie.update(cat, LONG_STRING);
|
||||||
assertEquals(LONG_STRING, trie.get(cat));
|
assertEquals(LONG_STRING, new String(trie.get(cat)));
|
||||||
assertEquals(ROOT_HASH_BEFORE, trie.getRootHash());
|
assertEquals(ROOT_HASH_BEFORE, Hex.toHexString(trie.getRootHash()));
|
||||||
|
|
||||||
trie.delete(ca);
|
trie.delete(ca);
|
||||||
assertEquals("", trie.get(ca));
|
assertEquals("", new String(trie.get(ca)));
|
||||||
assertEquals(ROOT_HASH_AFTER1, trie.getRootHash());
|
assertEquals(ROOT_HASH_AFTER1, Hex.toHexString(trie.getRootHash()));
|
||||||
|
|
||||||
trie.delete(cat);
|
trie.delete(cat);
|
||||||
assertEquals("", trie.get(cat));
|
assertEquals("", new String(trie.get(cat)));
|
||||||
assertEquals(ROOT_HASH_AFTER2, trie.getRootHash());
|
assertEquals(ROOT_HASH_AFTER2, Hex.toHexString(trie.getRootHash()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testDeleteAll() {
|
public void testDeleteAll() {
|
||||||
String ROOT_HASH_BEFORE = "a84739b4762ddf15e3acc4e6957e5ab2bbfaaef00fe9d436a7369c6f058ec90d";
|
String ROOT_HASH_BEFORE = "a84739b4762ddf15e3acc4e6957e5ab2bbfaaef00fe9d436a7369c6f058ec90d";
|
||||||
Trie trie = new Trie(mockDb);
|
Trie trie = new Trie(mockDb);
|
||||||
assertEquals(ROOT_HASH_EMPTY, trie.getRootHash());
|
assertEquals(ROOT_HASH_EMPTY, Hex.toHexString(trie.getRootHash()));
|
||||||
|
|
||||||
trie.update(ca, dude);
|
trie.update(ca, dude);
|
||||||
trie.update(cat, dog);
|
trie.update(cat, dog);
|
||||||
trie.update(doge, LONG_STRING);
|
trie.update(doge, LONG_STRING);
|
||||||
assertEquals(ROOT_HASH_BEFORE, trie.getRootHash());
|
assertEquals(ROOT_HASH_BEFORE, Hex.toHexString(trie.getRootHash()));
|
||||||
|
|
||||||
trie.delete(ca);
|
trie.delete(ca);
|
||||||
trie.delete(cat);
|
trie.delete(cat);
|
||||||
trie.delete(doge);
|
trie.delete(doge);
|
||||||
assertEquals(ROOT_HASH_EMPTY, trie.getRootHash());
|
assertEquals(ROOT_HASH_EMPTY, Hex.toHexString(trie.getRootHash()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -339,12 +340,12 @@ public class TrieTest {
|
||||||
trie1.update(doge, LONG_STRING);
|
trie1.update(doge, LONG_STRING);
|
||||||
trie2.update(doge, LONG_STRING);
|
trie2.update(doge, LONG_STRING);
|
||||||
assertTrue("Expected tries to be equal", trie1.cmp(trie2));
|
assertTrue("Expected tries to be equal", trie1.cmp(trie2));
|
||||||
assertEquals(trie1.getRootHash(), trie2.getRootHash());
|
assertEquals(Hex.toHexString(trie1.getRootHash()), Hex.toHexString(trie2.getRootHash()));
|
||||||
|
|
||||||
trie1.update(dog, LONG_STRING);
|
trie1.update(dog, LONG_STRING);
|
||||||
trie2.update(cat, LONG_STRING);
|
trie2.update(cat, LONG_STRING);
|
||||||
assertFalse("Expected tries not to be equal", trie1.cmp(trie2));
|
assertFalse("Expected tries not to be equal", trie1.cmp(trie2));
|
||||||
assertNotEquals(trie1.getRootHash(), trie2.getRootHash());
|
assertNotEquals(Hex.toHexString(trie1.getRootHash()), Hex.toHexString(trie2.getRootHash()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -386,12 +387,26 @@ public class TrieTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testTrieCopy() {
|
public void testTrieCopy() {
|
||||||
fail("To be implemented");
|
Trie trie = new Trie(mockDb);
|
||||||
|
trie.update("doe", "reindeer");
|
||||||
|
Trie trie2 = trie.copy();
|
||||||
|
assertFalse(trie.equals(trie2)); // avoid possibility that its just a reference copy
|
||||||
|
assertEquals(Hex.toHexString(trie.getRootHash()), Hex.toHexString(trie2.getRootHash()));
|
||||||
|
assertTrue(trie.cmp(trie2));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testTrieUndo() {
|
public void testTrieUndo() {
|
||||||
fail("To be implemented");
|
Trie trie = new Trie(mockDb);
|
||||||
|
trie.update("doe", "reindeer");
|
||||||
|
assertEquals("11a0327cfcc5b7689b6b6d727e1f5f8846c1137caaa9fc871ba31b7cce1b703e", Hex.toHexString(trie.getRootHash()));
|
||||||
|
trie.sync();
|
||||||
|
|
||||||
|
trie.update("dog", "puppy");
|
||||||
|
assertEquals("05ae693aac2107336a79309e0c60b24a7aac6aa3edecaef593921500d33c63c4", Hex.toHexString(trie.getRootHash()));
|
||||||
|
|
||||||
|
trie.undo();
|
||||||
|
assertEquals("11a0327cfcc5b7689b6b6d727e1f5f8846c1137caaa9fc871ba31b7cce1b703e", Hex.toHexString(trie.getRootHash()));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Using tests from: https://github.com/ethereum/tests/blob/master/trietest.json
|
// Using tests from: https://github.com/ethereum/tests/blob/master/trietest.json
|
||||||
|
@ -401,20 +416,20 @@ public class TrieTest {
|
||||||
Trie trie = new Trie(mockDb);
|
Trie trie = new Trie(mockDb);
|
||||||
trie.update("A", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa");
|
trie.update("A", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa");
|
||||||
|
|
||||||
assertEquals("d23786fb4a010da3ce639d66d5e904a11dbc02746d1ce25029e53290cabf28ab", trie.getRootHash());
|
assertEquals("d23786fb4a010da3ce639d66d5e904a11dbc02746d1ce25029e53290cabf28ab", Hex.toHexString(trie.getRootHash()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testDogs() {
|
public void testDogs() {
|
||||||
Trie trie = new Trie(mockDb);
|
Trie trie = new Trie(mockDb);
|
||||||
trie.update("doe", "reindeer");
|
trie.update("doe", "reindeer");
|
||||||
assertEquals("11a0327cfcc5b7689b6b6d727e1f5f8846c1137caaa9fc871ba31b7cce1b703e", trie.getRootHash());
|
assertEquals("11a0327cfcc5b7689b6b6d727e1f5f8846c1137caaa9fc871ba31b7cce1b703e", Hex.toHexString(trie.getRootHash()));
|
||||||
|
|
||||||
trie.update("dog", "puppy");
|
trie.update("dog", "puppy");
|
||||||
assertEquals("05ae693aac2107336a79309e0c60b24a7aac6aa3edecaef593921500d33c63c4", trie.getRootHash());
|
assertEquals("05ae693aac2107336a79309e0c60b24a7aac6aa3edecaef593921500d33c63c4", Hex.toHexString(trie.getRootHash()));
|
||||||
|
|
||||||
trie.update("dogglesworth", "cat");
|
trie.update("dogglesworth", "cat");
|
||||||
assertEquals("8aad789dff2f538bca5d8ea56e8abe10f4c7ba3a5dea95fea4cd6e7c3a1168d3", trie.getRootHash());
|
assertEquals("8aad789dff2f538bca5d8ea56e8abe10f4c7ba3a5dea95fea4cd6e7c3a1168d3", Hex.toHexString(trie.getRootHash()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -425,7 +440,7 @@ public class TrieTest {
|
||||||
trie.update("doge", "coin");
|
trie.update("doge", "coin");
|
||||||
trie.update("dog", "puppy");
|
trie.update("dog", "puppy");
|
||||||
|
|
||||||
assertEquals("5991bb8c6514148a29db676a14ac506cd2cd5775ace63c30a4fe457715e9ac84", trie.getRootHash());
|
assertEquals("5991bb8c6514148a29db676a14ac506cd2cd5775ace63c30a4fe457715e9ac84", Hex.toHexString(trie.getRootHash()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -440,7 +455,7 @@ public class TrieTest {
|
||||||
trie.update("dog", "puppy");
|
trie.update("dog", "puppy");
|
||||||
trie.update("shaman", "");
|
trie.update("shaman", "");
|
||||||
|
|
||||||
assertEquals("5991bb8c6514148a29db676a14ac506cd2cd5775ace63c30a4fe457715e9ac84", trie.getRootHash());
|
assertEquals("5991bb8c6514148a29db676a14ac506cd2cd5775ace63c30a4fe457715e9ac84", Hex.toHexString(trie.getRootHash()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -450,7 +465,7 @@ public class TrieTest {
|
||||||
trie.update("food", "bat");
|
trie.update("food", "bat");
|
||||||
trie.update("food", "bass");
|
trie.update("food", "bass");
|
||||||
|
|
||||||
assertEquals("17beaa1648bafa633cda809c90c04af50fc8aed3cb40d16efbddee6fdf63c4c3", trie.getRootHash());
|
assertEquals("17beaa1648bafa633cda809c90c04af50fc8aed3cb40d16efbddee6fdf63c4c3", Hex.toHexString(trie.getRootHash()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -460,7 +475,7 @@ public class TrieTest {
|
||||||
trie.update("be", "e");
|
trie.update("be", "e");
|
||||||
trie.update("dog", "puppy");
|
trie.update("dog", "puppy");
|
||||||
trie.update("bed", "d");
|
trie.update("bed", "d");
|
||||||
assertEquals("3f67c7a47520f79faa29255d2d3c084a7a6df0453116ed7232ff10277a8be68b", trie.getRootHash());
|
assertEquals("3f67c7a47520f79faa29255d2d3c084a7a6df0453116ed7232ff10277a8be68b", Hex.toHexString(trie.getRootHash()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -468,9 +483,9 @@ public class TrieTest {
|
||||||
Trie trie = new Trie(mockDb);
|
Trie trie = new Trie(mockDb);
|
||||||
|
|
||||||
trie.update("test", "test");
|
trie.update("test", "test");
|
||||||
assertEquals("85d106d4edff3b7a4889e91251d0a87d7c17a1dda648ebdba8c6060825be23b8", trie.getRootHash());
|
assertEquals("85d106d4edff3b7a4889e91251d0a87d7c17a1dda648ebdba8c6060825be23b8", Hex.toHexString(trie.getRootHash()));
|
||||||
|
|
||||||
trie.update("te", "testy");
|
trie.update("te", "testy");
|
||||||
assertEquals("8452568af70d8d140f58d941338542f645fcca50094b20f3c3d8c3df49337928", trie.getRootHash());
|
assertEquals("8452568af70d8d140f58d941338542f645fcca50094b20f3c3d8c3df49337928", Hex.toHexString(trie.getRootHash()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -85,7 +85,7 @@ public class RLPTest {
|
||||||
BigInteger peerId = RLP.decodeBigInteger(payload, nextIndex);
|
BigInteger peerId = RLP.decodeBigInteger(payload, nextIndex);
|
||||||
|
|
||||||
BigInteger expectedPeerId =
|
BigInteger expectedPeerId =
|
||||||
new BigInteger("-3757679129454624401847229560118336025674165800491763435653406124634392418475888088940922052683656239666728251000337405781915693264977453978537202650777524");
|
new BigInteger("9650128800487972697726795438087510101805200020100629942070155319087371611597658887860952245483247188023303607186148645071838189546969115967896446355306572");
|
||||||
assertEquals(expectedPeerId, peerId);
|
assertEquals(expectedPeerId, peerId);
|
||||||
|
|
||||||
nextIndex = RLP.getNextElementIndex(payload, nextIndex);
|
nextIndex = RLP.getNextElementIndex(payload, nextIndex);
|
||||||
|
@ -101,7 +101,7 @@ public class RLPTest {
|
||||||
peerId = RLP.decodeBigInteger(payload, nextIndex);
|
peerId = RLP.decodeBigInteger(payload, nextIndex);
|
||||||
|
|
||||||
expectedPeerId =
|
expectedPeerId =
|
||||||
new BigInteger("-3757679129454624401847229560118336025674165800491763435653406124634392418475888088940922052683656239666728251000337405781915693264977453978537202650777524");
|
new BigInteger("9650128800487972697726795438087510101805200020100629942070155319087371611597658887860952245483247188023303607186148645071838189546969115967896446355306572");
|
||||||
|
|
||||||
assertEquals(expectedPeerId ,peerId);
|
assertEquals(expectedPeerId ,peerId);
|
||||||
|
|
||||||
|
@ -429,7 +429,7 @@ public class RLPTest {
|
||||||
assertEquals(expected, Hex.toHexString(encoderesult));
|
assertEquals(expected, Hex.toHexString(encoderesult));
|
||||||
|
|
||||||
byte[] decodeResult = (byte[]) RLP.decode(encoderesult, 0).getDecoded();
|
byte[] decodeResult = (byte[]) RLP.decode(encoderesult, 0).getDecoded();
|
||||||
assertEquals(test, new BigInteger(decodeResult));
|
assertEquals(test, new BigInteger(1, decodeResult));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -615,10 +615,10 @@ public class RLPTest {
|
||||||
assertEquals(test11, byteArrayToInt(decodedData));
|
assertEquals(test11, byteArrayToInt(decodedData));
|
||||||
|
|
||||||
decodedData = (byte[]) RLP.decode(Hex.decode(result12), pos).getDecoded();
|
decodedData = (byte[]) RLP.decode(Hex.decode(result12), pos).getDecoded();
|
||||||
assertTrue(test12.compareTo(new BigInteger(decodedData)) == 0);
|
assertTrue(test12.compareTo(new BigInteger(1, decodedData)) == 0);
|
||||||
|
|
||||||
decodedData = (byte[]) RLP.decode(Hex.decode(result13), pos).getDecoded();
|
decodedData = (byte[]) RLP.decode(Hex.decode(result13), pos).getDecoded();
|
||||||
assertTrue(test13.compareTo(new BigInteger(decodedData)) == 0);
|
assertTrue(test13.compareTo(new BigInteger(1, decodedData)) == 0);
|
||||||
|
|
||||||
// Need to test with different expected value, because decoding doesn't recognize types
|
// Need to test with different expected value, because decoding doesn't recognize types
|
||||||
Object testObject1 = RLP.decode(Hex.decode(result14), pos).getDecoded();
|
Object testObject1 = RLP.decode(Hex.decode(result14), pos).getDecoded();
|
||||||
|
|
|
@ -41,7 +41,7 @@ public class RlpTestData {
|
||||||
public static String result11 = "8203e8";
|
public static String result11 = "8203e8";
|
||||||
|
|
||||||
public static BigInteger test12 = new BigInteger("115792089237316195423570985008687907853269984665640564039457584007913129639935");
|
public static BigInteger test12 = new BigInteger("115792089237316195423570985008687907853269984665640564039457584007913129639935");
|
||||||
public static String result12 = "a100ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff";
|
public static String result12 = "a0ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff";
|
||||||
|
|
||||||
public static BigInteger test13 = new BigInteger("115792089237316195423570985008687907853269984665640564039457584007913129639936");
|
public static BigInteger test13 = new BigInteger("115792089237316195423570985008687907853269984665640564039457584007913129639936");
|
||||||
public static String result13 = "a1010000000000000000000000000000000000000000000000000000000000000000";
|
public static String result13 = "a1010000000000000000000000000000000000000000000000000000000000000000";
|
||||||
|
|
|
@ -17,7 +17,7 @@ public class UtilsTest {
|
||||||
@Test
|
@Test
|
||||||
public void getValueShortString1(){
|
public void getValueShortString1(){
|
||||||
|
|
||||||
String expected = "123 (10^24)";
|
String expected = "123·(10^24)";
|
||||||
String result = Utils.getValueShortString(new BigInteger("123456789123445654363653463"));
|
String result = Utils.getValueShortString(new BigInteger("123456789123445654363653463"));
|
||||||
|
|
||||||
assertEquals(expected, result);
|
assertEquals(expected, result);
|
||||||
|
@ -26,7 +26,7 @@ public class UtilsTest {
|
||||||
@Test
|
@Test
|
||||||
public void getValueShortString2(){
|
public void getValueShortString2(){
|
||||||
|
|
||||||
String expected = "123 (10^3)";
|
String expected = "123·(10^3)";
|
||||||
String result = Utils.getValueShortString(new BigInteger("123456"));
|
String result = Utils.getValueShortString(new BigInteger("123456"));
|
||||||
|
|
||||||
assertEquals(expected, result);
|
assertEquals(expected, result);
|
||||||
|
@ -35,7 +35,7 @@ public class UtilsTest {
|
||||||
@Test
|
@Test
|
||||||
public void getValueShortString3(){
|
public void getValueShortString3(){
|
||||||
|
|
||||||
String expected = "1 (10^3)";
|
String expected = "1·(10^3)";
|
||||||
String result = Utils.getValueShortString(new BigInteger("1234"));
|
String result = Utils.getValueShortString(new BigInteger("1234"));
|
||||||
|
|
||||||
assertEquals(expected, result);
|
assertEquals(expected, result);
|
||||||
|
@ -44,7 +44,7 @@ public class UtilsTest {
|
||||||
@Test
|
@Test
|
||||||
public void getValueShortString4(){
|
public void getValueShortString4(){
|
||||||
|
|
||||||
String expected = "123 (10^0)";
|
String expected = "123·(10^0)";
|
||||||
String result = Utils.getValueShortString(new BigInteger("123"));
|
String result = Utils.getValueShortString(new BigInteger("123"));
|
||||||
|
|
||||||
assertEquals(expected, result);
|
assertEquals(expected, result);
|
||||||
|
@ -54,7 +54,7 @@ public class UtilsTest {
|
||||||
public void getValueShortString5(){
|
public void getValueShortString5(){
|
||||||
|
|
||||||
byte[] decimal = Hex.decode("3913517ebd3c0c65000000");
|
byte[] decimal = Hex.decode("3913517ebd3c0c65000000");
|
||||||
String expected = "69 (10^24)";
|
String expected = "69·(10^24)";
|
||||||
String result = Utils.getValueShortString(new BigInteger(decimal));
|
String result = Utils.getValueShortString(new BigInteger(decimal));
|
||||||
|
|
||||||
assertEquals(expected, result);
|
assertEquals(expected, result);
|
||||||
|
|
Loading…
Reference in New Issue