Use Repository as abstraction layer for Blockchain
This commit is contained in:
parent
d8063c5ff3
commit
2b42ebaac2
|
@ -110,7 +110,7 @@ public class Block {
|
||||||
}
|
}
|
||||||
|
|
||||||
public Block getParent() {
|
public Block getParent() {
|
||||||
return WorldManager.getInstance().getBlockChain().getByNumber(this.getNumber() - 1);
|
return WorldManager.getInstance().getBlockchain().getByNumber(this.getNumber() - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
public byte[] getParentHash() {
|
public byte[] getParentHash() {
|
||||||
|
|
|
@ -1,17 +1,18 @@
|
||||||
package org.ethereum.core;
|
package org.ethereum.core;
|
||||||
|
|
||||||
import org.ethereum.db.DatabaseImpl;
|
import org.ethereum.db.Repository;
|
||||||
import org.ethereum.listener.EthereumListener;
|
import org.ethereum.listener.EthereumListener;
|
||||||
import org.ethereum.manager.WorldManager;
|
import org.ethereum.manager.WorldManager;
|
||||||
|
import org.ethereum.net.BlockQueue;
|
||||||
import org.ethereum.util.AdvancedDeviceUtils;
|
import org.ethereum.util.AdvancedDeviceUtils;
|
||||||
import org.ethereum.util.ByteUtil;
|
import org.ethereum.vm.*;
|
||||||
import org.iq80.leveldb.DBIterator;
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.spongycastle.util.encoders.Hex;
|
import org.spongycastle.util.encoders.Hex;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.math.BigInteger;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
@ -53,21 +54,39 @@ import static org.ethereum.core.Denomination.SZABO;
|
||||||
public class Blockchain {
|
public class Blockchain {
|
||||||
|
|
||||||
private static Logger logger = LoggerFactory.getLogger("blockchain");
|
private static Logger logger = LoggerFactory.getLogger("blockchain");
|
||||||
|
private static Logger stateLogger = LoggerFactory.getLogger("state");
|
||||||
|
|
||||||
// to avoid using minGasPrice=0 from Genesis for the wallet
|
// to avoid using minGasPrice=0 from Genesis for the wallet
|
||||||
private static long INITIAL_MIN_GAS_PRICE = 10 * SZABO.longValue();
|
private static long INITIAL_MIN_GAS_PRICE = 10 * SZABO.longValue();
|
||||||
|
|
||||||
private DatabaseImpl chainDb;
|
private Repository repository;
|
||||||
|
|
||||||
private Block lastBlock;
|
private Block lastBlock;
|
||||||
|
|
||||||
// keep the index of the chain for
|
// keep the index of the chain for
|
||||||
// convenient usage, <block_number, block_hash>
|
// convenient usage, <block_number, block_hash>
|
||||||
private Map<Long, byte[]> index = new HashMap<>();
|
private Map<Long, byte[]> blockCache = new HashMap<>();
|
||||||
|
|
||||||
|
private Map<String, Transaction> pendingTransactions = Collections
|
||||||
|
.synchronizedMap(new HashMap<String, Transaction>());
|
||||||
|
|
||||||
|
private BlockQueue blockQueue = new BlockQueue();
|
||||||
|
|
||||||
public Blockchain() {
|
public Blockchain(Repository repository) {
|
||||||
this.chainDb = new DatabaseImpl("blockchain");
|
this.repository = repository;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public BlockQueue getBlockQueue() {
|
||||||
|
return blockQueue;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<Long, byte[]> getBlockCache() {
|
||||||
|
return this.blockCache;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getGasPrice() {
|
||||||
|
// In case of the genesis block we don't want to rely on the min gas price
|
||||||
|
return lastBlock.isGenesis() ? lastBlock.getMinGasPrice() : INITIAL_MIN_GAS_PRICE;
|
||||||
|
}
|
||||||
|
|
||||||
public Block getLastBlock() {
|
public Block getLastBlock() {
|
||||||
return lastBlock;
|
return lastBlock;
|
||||||
|
@ -77,12 +96,19 @@ public class Blockchain {
|
||||||
this.lastBlock = block;
|
this.lastBlock = block;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public byte[] getLatestBlockHash() {
|
||||||
|
if (blockCache.isEmpty())
|
||||||
|
return Genesis.getInstance().getHash();
|
||||||
|
else
|
||||||
|
return getLastBlock().getHash();
|
||||||
|
}
|
||||||
|
|
||||||
public int getSize() {
|
public int getSize() {
|
||||||
return index.size();
|
return blockCache.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Block getByNumber(long blockNr) {
|
public Block getByNumber(long blockNr) {
|
||||||
return new Block(chainDb.get(ByteUtil.longToBytes(blockNr)));
|
return repository.getBlock(blockNr);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void add(Block block) {
|
public void add(Block block) {
|
||||||
|
@ -92,13 +118,13 @@ public class Blockchain {
|
||||||
|
|
||||||
// if it is the first block to add
|
// if it is the first block to add
|
||||||
// make sure the parent is genesis
|
// make sure the parent is genesis
|
||||||
if (index.isEmpty()
|
if (blockCache.isEmpty()
|
||||||
&& !Arrays.equals(Genesis.getInstance().getHash(),
|
&& !Arrays.equals(Genesis.getInstance().getHash(),
|
||||||
block.getParentHash())) {
|
block.getParentHash())) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// if there is some blocks already keep chain continuity
|
// if there is some blocks already keep chain continuity
|
||||||
if (!index.isEmpty()) {
|
if (!blockCache.isEmpty()) {
|
||||||
String hashLast = Hex.toHexString(getLastBlock().getHash());
|
String hashLast = Hex.toHexString(getLastBlock().getHash());
|
||||||
String blockParentHash = Hex.toHexString(block.getParentHash());
|
String blockParentHash = Hex.toHexString(block.getParentHash());
|
||||||
if (!hashLast.equals(blockParentHash)) return;
|
if (!hashLast.equals(blockParentHash)) return;
|
||||||
|
@ -120,16 +146,7 @@ public class Blockchain {
|
||||||
EthereumListener listener = WorldManager.getInstance().getListener();
|
EthereumListener listener = WorldManager.getInstance().getListener();
|
||||||
if (listener != null)
|
if (listener != null)
|
||||||
listener.trace(String.format("Block chain size: [ %d ]", this.getSize()));
|
listener.trace(String.format("Block chain size: [ %d ]", this.getSize()));
|
||||||
|
|
||||||
/*
|
|
||||||
if (lastBlock.getNumber() >= 30) {
|
|
||||||
System.out.println("** checkpoint **");
|
|
||||||
|
|
||||||
this.close();
|
|
||||||
WorldManager.getInstance().getRepository().close();
|
|
||||||
System.exit(1);
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void processBlock(Block block) {
|
public void processBlock(Block block) {
|
||||||
|
@ -138,7 +155,7 @@ public class Blockchain {
|
||||||
for (Transaction tx : block.getTransactionsList())
|
for (Transaction tx : block.getTransactionsList())
|
||||||
// TODO: refactor the wallet pending transactions to the world manager
|
// TODO: refactor the wallet pending transactions to the world manager
|
||||||
WorldManager.getInstance().addWalletTransaction(tx);
|
WorldManager.getInstance().addWalletTransaction(tx);
|
||||||
WorldManager.getInstance().applyBlock(block);
|
this.applyBlock(block);
|
||||||
WorldManager.getInstance().getWallet().processBlock(block);
|
WorldManager.getInstance().getWallet().processBlock(block);
|
||||||
}
|
}
|
||||||
this.storeBlock(block);
|
this.storeBlock(block);
|
||||||
|
@ -147,7 +164,7 @@ public class Blockchain {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void storeBlock(Block block) {
|
public void storeBlock(Block block) {
|
||||||
/* Debug check to see if the state is still as expected */
|
/* Debug check to see if the state is still as expected */
|
||||||
if(logger.isWarnEnabled()) {
|
if(logger.isWarnEnabled()) {
|
||||||
String blockStateRootHash = Hex.toHexString(block.getStateRoot());
|
String blockStateRootHash = Hex.toHexString(block.getStateRoot());
|
||||||
|
@ -155,12 +172,13 @@ public class Blockchain {
|
||||||
if(!blockStateRootHash.equals(worldStateRootHash)){
|
if(!blockStateRootHash.equals(worldStateRootHash)){
|
||||||
logger.error("ERROR: STATE CONFLICT! block: {} worldstate {} mismatch", block.getNumber(), worldStateRootHash);
|
logger.error("ERROR: STATE CONFLICT! block: {} worldstate {} mismatch", block.getNumber(), worldStateRootHash);
|
||||||
// Last conflict on block 1157 -> worldstate b1d9a978451ef04c1639011d9516473d51c608dbd25906c89be791707008d2de
|
// Last conflict on block 1157 -> worldstate b1d9a978451ef04c1639011d9516473d51c608dbd25906c89be791707008d2de
|
||||||
|
repository.close();
|
||||||
System.exit(-1); // Don't add block
|
System.exit(-1); // Don't add block
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.chainDb.put(ByteUtil.longToBytes(block.getNumber()), block.getEncoded());
|
this.repository.saveBlock(block);
|
||||||
this.index.put(block.getNumber(), block.getHash());
|
this.blockCache.put(block.getNumber(), block.getHash());
|
||||||
this.setLastBlock(block);
|
this.setLastBlock(block);
|
||||||
|
|
||||||
if (logger.isDebugEnabled())
|
if (logger.isDebugEnabled())
|
||||||
|
@ -168,46 +186,233 @@ public class Blockchain {
|
||||||
logger.info("*** Block chain size: [ {} ]", this.getSize());
|
logger.info("*** Block chain size: [ {} ]", this.getSize());
|
||||||
}
|
}
|
||||||
|
|
||||||
public long getGasPrice() {
|
public void applyBlock(Block block) {
|
||||||
// In case of the genesis block we don't want to rely on the min gas price
|
|
||||||
return lastBlock.isGenesis() ? lastBlock.getMinGasPrice() : INITIAL_MIN_GAS_PRICE;
|
int i = 0;
|
||||||
}
|
for (Transaction tx : block.getTransactionsList()) {
|
||||||
|
stateLogger.debug("apply block: [ {} ] tx: [ {} ] ", block.getNumber(), i);
|
||||||
|
applyTransaction(block, tx, block.getCoinbase());
|
||||||
|
repository.dumpState(block.getNumber(), i, tx.getHash());
|
||||||
|
++i;
|
||||||
|
|
||||||
public byte[] getLatestBlockHash() {
|
}
|
||||||
if (index.isEmpty())
|
|
||||||
return Genesis.getInstance().getHash();
|
// miner reward
|
||||||
else
|
if (repository.getAccountState(block.getCoinbase()) == null)
|
||||||
return getLastBlock().getHash();
|
repository.createAccount(block.getCoinbase());
|
||||||
}
|
repository.addBalance(block.getCoinbase(), Block.BLOCK_REWARD);
|
||||||
|
for (Block uncle : block.getUncleList()) {
|
||||||
|
repository.addBalance(uncle.getCoinbase(), Block.UNCLE_REWARD);
|
||||||
|
}
|
||||||
|
|
||||||
|
repository.dumpState(block.getNumber(), 0,
|
||||||
|
null);
|
||||||
|
}
|
||||||
|
|
||||||
public void load() {
|
public void applyTransaction(Block block, Transaction tx, byte[] coinbase) {
|
||||||
DBIterator iterator = chainDb.iterator();
|
|
||||||
try {
|
byte[] senderAddress = tx.getSender();
|
||||||
if (!iterator.hasNext()) {
|
AccountState senderAccount = repository.getAccountState(senderAddress);
|
||||||
logger.info("DB is empty - adding Genesis");
|
|
||||||
this.lastBlock = Genesis.getInstance();
|
if (senderAccount == null) {
|
||||||
this.storeBlock(lastBlock);
|
if (stateLogger.isWarnEnabled())
|
||||||
logger.debug("Block #{} -> {}", Genesis.NUMBER, lastBlock.toFlatString());
|
stateLogger.warn("No such address: {}",
|
||||||
} else {
|
Hex.toHexString(senderAddress));
|
||||||
logger.debug("Displaying blocks stored in DB sorted on blocknumber");
|
return;
|
||||||
for (iterator.seekToFirst(); iterator.hasNext();) {
|
}
|
||||||
this.lastBlock = new Block(iterator.next().getValue());
|
|
||||||
this.index.put(lastBlock.getNumber(), lastBlock.getHash());
|
// 1. VALIDATE THE NONCE
|
||||||
logger.debug("Block #{} -> {}", lastBlock.getNumber(), lastBlock.toFlatString());
|
BigInteger nonce = senderAccount.getNonce();
|
||||||
}
|
BigInteger txNonce = new BigInteger(1, tx.getNonce());
|
||||||
}
|
if (nonce.compareTo(txNonce) != 0) {
|
||||||
} finally {
|
if (stateLogger.isWarnEnabled())
|
||||||
// Make sure you close the iterator to avoid resource leaks.
|
stateLogger.warn("Invalid nonce account.nonce={} tx.nonce={}",
|
||||||
try {
|
nonce, txNonce);
|
||||||
iterator.close();
|
return;
|
||||||
} catch (IOException e) {
|
}
|
||||||
logger.error(e.getMessage(), e);
|
|
||||||
|
// 3. FIND OUT THE TRANSACTION TYPE
|
||||||
|
byte[] receiverAddress, code = null;
|
||||||
|
boolean isContractCreation = tx.isContractCreation();
|
||||||
|
if (isContractCreation) {
|
||||||
|
receiverAddress = tx.getContractAddress();
|
||||||
|
repository.createAccount(receiverAddress);
|
||||||
|
if(stateLogger.isDebugEnabled())
|
||||||
|
stateLogger.debug("new contract created address={}",
|
||||||
|
Hex.toHexString(receiverAddress));
|
||||||
|
code = tx.getData(); // init code
|
||||||
|
if (stateLogger.isDebugEnabled())
|
||||||
|
stateLogger.debug("running the init for contract: address={}",
|
||||||
|
Hex.toHexString(receiverAddress));
|
||||||
|
} else {
|
||||||
|
receiverAddress = tx.getReceiveAddress();
|
||||||
|
AccountState receiverState = repository.getAccountState(receiverAddress);
|
||||||
|
if (receiverState == null) {
|
||||||
|
repository.createAccount(receiverAddress);
|
||||||
|
if (stateLogger.isDebugEnabled())
|
||||||
|
stateLogger.debug("new receiver account created address={}",
|
||||||
|
Hex.toHexString(receiverAddress));
|
||||||
|
} else {
|
||||||
|
code = repository.getCode(receiverAddress);
|
||||||
|
if (code != null) {
|
||||||
|
if (stateLogger.isDebugEnabled())
|
||||||
|
stateLogger.debug("calling for existing contract: address={}",
|
||||||
|
Hex.toHexString(receiverAddress));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 2.1 UPDATE THE NONCE
|
||||||
|
// (THIS STAGE IS NOT REVERTED BY ANY EXCEPTION)
|
||||||
|
repository.increaseNonce(senderAddress);
|
||||||
|
|
||||||
|
// 2.2 PERFORM THE GAS VALUE TX
|
||||||
|
// (THIS STAGE IS NOT REVERTED BY ANY EXCEPTION)
|
||||||
|
BigInteger gasDebit = tx.getTotalGasValueDebit();
|
||||||
|
|
||||||
|
// Debit the actual total gas value from the sender
|
||||||
|
// the purchased gas will be available for
|
||||||
|
// the contract in the execution state,
|
||||||
|
// it can be retrieved using GAS op
|
||||||
|
if (gasDebit.signum() == 1) {
|
||||||
|
BigInteger balance = senderAccount.getBalance();
|
||||||
|
if (balance.compareTo(gasDebit) == -1) {
|
||||||
|
logger.debug("No gas to start the execution: sender={}",
|
||||||
|
Hex.toHexString(senderAddress));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
repository.addBalance(senderAddress, gasDebit.negate());
|
||||||
|
|
||||||
|
// The coinbase get the gas cost
|
||||||
|
if (coinbase != null)
|
||||||
|
repository.addBalance(coinbase, gasDebit);
|
||||||
|
|
||||||
|
if (stateLogger.isDebugEnabled())
|
||||||
|
stateLogger.debug(
|
||||||
|
"Before contract execution debit the sender address with gas total cost, "
|
||||||
|
+ "\n sender={} \n gas_debit= {}",
|
||||||
|
Hex.toHexString(senderAddress), gasDebit);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. START TRACKING FOR REVERT CHANGES OPTION !!!
|
||||||
|
Repository trackRepository = repository.getTrack();
|
||||||
|
trackRepository.startTracking();
|
||||||
|
|
||||||
|
try {
|
||||||
|
|
||||||
|
// 4. THE SIMPLE VALUE/BALANCE CHANGE
|
||||||
|
if (tx.getValue() != null) {
|
||||||
|
|
||||||
|
BigInteger senderBalance = senderAccount.getBalance();
|
||||||
|
|
||||||
|
if (senderBalance.compareTo(new BigInteger(1, tx.getValue())) >= 0) {
|
||||||
|
repository.addBalance(receiverAddress,
|
||||||
|
new BigInteger(1, tx.getValue()));
|
||||||
|
repository.addBalance(senderAddress,
|
||||||
|
new BigInteger(1, tx.getValue()).negate());
|
||||||
|
|
||||||
|
if (stateLogger.isDebugEnabled())
|
||||||
|
stateLogger.debug("Update value balance \n "
|
||||||
|
+ "sender={}, receiver={}, value={}",
|
||||||
|
Hex.toHexString(senderAddress),
|
||||||
|
Hex.toHexString(receiverAddress),
|
||||||
|
new BigInteger(tx.getValue()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 5. CREATE OR EXECUTE PROGRAM
|
||||||
|
if (isContractCreation || code != null) {
|
||||||
|
Block currBlock = (block == null) ? this.getLastBlock() : block;
|
||||||
|
|
||||||
|
ProgramInvoke programInvoke = ProgramInvokeFactory
|
||||||
|
.createProgramInvoke(tx, currBlock, trackRepository);
|
||||||
|
|
||||||
|
VM vm = new VM();
|
||||||
|
Program program = new Program(code, programInvoke);
|
||||||
|
|
||||||
|
if (CONFIG.playVM())
|
||||||
|
vm.play(program);
|
||||||
|
ProgramResult result = program.getResult();
|
||||||
|
applyProgramResult(result, gasDebit, trackRepository,
|
||||||
|
senderAddress, receiverAddress, coinbase, isContractCreation);
|
||||||
|
} else {
|
||||||
|
// refund everything except fee (500 + 5*txdata)
|
||||||
|
BigInteger gasPrice = new BigInteger(1, tx.getGasPrice());
|
||||||
|
long dataFee = tx.getData() == null ? 0: tx.getData().length * GasCost.TXDATA;
|
||||||
|
long minTxFee = GasCost.TRANSACTION + dataFee;
|
||||||
|
BigInteger refund = gasDebit.subtract(BigInteger.valueOf(
|
||||||
|
minTxFee).multiply(gasPrice));
|
||||||
|
if (refund.signum() > 0) {
|
||||||
|
// gas refund
|
||||||
|
repository.addBalance(senderAddress, refund);
|
||||||
|
repository.addBalance(coinbase, refund.negate());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (RuntimeException e) {
|
||||||
|
trackRepository.rollback();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
trackRepository.commit();
|
||||||
|
pendingTransactions.put(Hex.toHexString(tx.getHash()), tx);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void close() {
|
/**
|
||||||
if (this.chainDb != null)
|
* After any contract code finish the run the certain result should take
|
||||||
chainDb.close();
|
* place, according the given circumstances
|
||||||
}
|
*
|
||||||
|
* @param result
|
||||||
|
* @param gasDebit
|
||||||
|
* @param senderAddress
|
||||||
|
* @param contractAddress
|
||||||
|
*/
|
||||||
|
private void applyProgramResult(ProgramResult result, BigInteger gasDebit,
|
||||||
|
Repository repository, byte[] senderAddress,
|
||||||
|
byte[] contractAddress, byte[] coinbase, boolean initResults) {
|
||||||
|
|
||||||
|
if (result.getException() != null
|
||||||
|
&& result.getException() instanceof Program.OutOfGasException) {
|
||||||
|
stateLogger.debug("contract run halted by OutOfGas: contract={}",
|
||||||
|
Hex.toHexString(contractAddress));
|
||||||
|
throw result.getException();
|
||||||
|
}
|
||||||
|
|
||||||
|
BigInteger gasPrice = BigInteger.valueOf(this.getGasPrice());
|
||||||
|
BigInteger refund = gasDebit.subtract(BigInteger.valueOf(
|
||||||
|
result.getGasUsed()).multiply(gasPrice));
|
||||||
|
|
||||||
|
if (refund.signum() > 0) {
|
||||||
|
if (stateLogger.isDebugEnabled())
|
||||||
|
stateLogger
|
||||||
|
.debug("After contract execution the sender address refunded with gas leftover, "
|
||||||
|
+ "\n sender={} \n contract={} \n gas_refund= {}",
|
||||||
|
Hex.toHexString(senderAddress),
|
||||||
|
Hex.toHexString(contractAddress), refund);
|
||||||
|
// gas refund
|
||||||
|
repository.addBalance(senderAddress, refund);
|
||||||
|
repository.addBalance(coinbase, refund.negate());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (initResults) {
|
||||||
|
// Save the code created by init
|
||||||
|
byte[] bodyCode = null;
|
||||||
|
if (result.getHReturn() != null) {
|
||||||
|
bodyCode = result.getHReturn().array();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bodyCode != null) {
|
||||||
|
if (stateLogger.isDebugEnabled())
|
||||||
|
stateLogger
|
||||||
|
.debug("saving code of the contract to the db:\n contract={} code={}",
|
||||||
|
Hex.toHexString(contractAddress),
|
||||||
|
Hex.toHexString(bodyCode));
|
||||||
|
repository.saveCode(contractAddress, bodyCode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// delete the marked to die accounts
|
||||||
|
if (result.getDeleteAccounts() == null) return;
|
||||||
|
for (DataWord address : result.getDeleteAccounts()){
|
||||||
|
repository.delete(address.getNoLeadZeroesData());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,15 +23,15 @@ public class ContractDetails {
|
||||||
|
|
||||||
private byte[] rlpEncoded;
|
private byte[] rlpEncoded;
|
||||||
|
|
||||||
private List<DataWord> storageKeys = new ArrayList<DataWord>();
|
private List<DataWord> storageKeys = new ArrayList<>();
|
||||||
private List<DataWord> storageValues = new ArrayList<DataWord>();
|
private List<DataWord> storageValues = new ArrayList<>();
|
||||||
|
|
||||||
private byte[] code;
|
private byte[] code;
|
||||||
|
|
||||||
private Trie storageTrie = new Trie(null);
|
private Trie storageTrie = new Trie(null);
|
||||||
|
|
||||||
public ContractDetails() {
|
public ContractDetails() {
|
||||||
}
|
}
|
||||||
|
|
||||||
public ContractDetails(byte[] rlpCode) {
|
public ContractDetails(byte[] rlpCode) {
|
||||||
decode(rlpCode);
|
decode(rlpCode);
|
||||||
|
@ -165,7 +165,7 @@ public class ContractDetails {
|
||||||
}
|
}
|
||||||
|
|
||||||
public Map<DataWord, DataWord> getStorage() {
|
public Map<DataWord, DataWord> getStorage() {
|
||||||
Map<DataWord, DataWord> storage = new HashMap<DataWord, DataWord>();
|
Map<DataWord, DataWord> storage = new HashMap<>();
|
||||||
for (int i = 0; storageKeys != null && i < storageKeys.size(); ++i) {
|
for (int i = 0; storageKeys != null && i < storageKeys.size(); ++i) {
|
||||||
storage.put(storageKeys.get(i), storageValues.get(i));
|
storage.put(storageKeys.get(i), storageValues.get(i));
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,9 @@ package org.ethereum.db;
|
||||||
|
|
||||||
import org.codehaus.plexus.util.FileUtils;
|
import org.codehaus.plexus.util.FileUtils;
|
||||||
import org.ethereum.core.AccountState;
|
import org.ethereum.core.AccountState;
|
||||||
|
import org.ethereum.core.Block;
|
||||||
|
import org.ethereum.core.Blockchain;
|
||||||
|
import org.ethereum.core.Genesis;
|
||||||
import org.ethereum.crypto.HashUtil;
|
import org.ethereum.crypto.HashUtil;
|
||||||
import org.ethereum.json.JSONHelper;
|
import org.ethereum.json.JSONHelper;
|
||||||
import org.ethereum.manager.WorldManager;
|
import org.ethereum.manager.WorldManager;
|
||||||
|
@ -9,6 +12,7 @@ import org.ethereum.trie.TrackTrie;
|
||||||
import org.ethereum.trie.Trie;
|
import org.ethereum.trie.Trie;
|
||||||
import org.ethereum.util.ByteUtil;
|
import org.ethereum.util.ByteUtil;
|
||||||
import org.ethereum.vm.DataWord;
|
import org.ethereum.vm.DataWord;
|
||||||
|
import org.iq80.leveldb.DBIterator;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.spongycastle.util.BigIntegers;
|
import org.spongycastle.util.BigIntegers;
|
||||||
|
@ -56,18 +60,25 @@ public class Repository {
|
||||||
// TODO: Listeners listeners
|
// TODO: Listeners listeners
|
||||||
// TODO: cash impl
|
// TODO: cash impl
|
||||||
|
|
||||||
private DatabaseImpl detailsDB = null;
|
private DatabaseImpl chainDB = null;
|
||||||
private DatabaseImpl stateDB = null;
|
private DatabaseImpl detailsDB = null;
|
||||||
|
private DatabaseImpl stateDB = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new Repository DAO
|
||||||
|
* assuming empty db and thus no stateRoot
|
||||||
|
*
|
||||||
|
* @See loadBlockchain() to update the stateRoot
|
||||||
|
*/
|
||||||
public Repository() {
|
public Repository() {
|
||||||
detailsDB = new DatabaseImpl("details");
|
chainDB = new DatabaseImpl("blockchain");
|
||||||
contractDetailsDB = new TrackDatabase(detailsDB);
|
detailsDB = new DatabaseImpl("details");
|
||||||
stateDB = new DatabaseImpl("state");
|
contractDetailsDB = new TrackDatabase(detailsDB);
|
||||||
worldState = new Trie(stateDB.getDb());
|
stateDB = new DatabaseImpl("state");
|
||||||
accountStateDB = new TrackTrie(worldState);
|
worldState = new Trie(stateDB.getDb());
|
||||||
|
accountStateDB = new TrackTrie(worldState);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private Repository(TrackTrie accountStateDB, TrackDatabase contractDetailsDB) {
|
private Repository(TrackTrie accountStateDB, TrackDatabase contractDetailsDB) {
|
||||||
this.accountStateDB = accountStateDB;
|
this.accountStateDB = accountStateDB;
|
||||||
this.contractDetailsDB = contractDetailsDB;
|
this.contractDetailsDB = contractDetailsDB;
|
||||||
|
@ -80,27 +91,72 @@ public class Repository {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void startTracking() {
|
public void startTracking() {
|
||||||
logger.info("start tracking");
|
logger.debug("start tracking");
|
||||||
accountStateDB.startTrack();
|
accountStateDB.startTrack();
|
||||||
contractDetailsDB.startTrack();
|
contractDetailsDB.startTrack();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void commit() {
|
public void commit() {
|
||||||
logger.info("commit changes");
|
logger.debug("commit changes");
|
||||||
accountStateDB.commitTrack();
|
accountStateDB.commitTrack();
|
||||||
contractDetailsDB.commitTrack();
|
contractDetailsDB.commitTrack();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void rollback() {
|
public void rollback() {
|
||||||
logger.info("rollback changes");
|
logger.debug("rollback changes");
|
||||||
accountStateDB.rollbackTrack();
|
accountStateDB.rollbackTrack();
|
||||||
contractDetailsDB.rollbackTrack();
|
contractDetailsDB.rollbackTrack();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Block getBlock(long blockNr) {
|
||||||
|
return new Block(chainDB.get(ByteUtil.longToBytes(blockNr)));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void saveBlock(Block block) {
|
||||||
|
this.chainDB.put(ByteUtil.longToBytes(block.getNumber()), block.getEncoded());
|
||||||
|
}
|
||||||
|
|
||||||
|
public Blockchain loadBlockchain() {
|
||||||
|
Blockchain blockchain = new Blockchain(this);
|
||||||
|
DBIterator iterator = chainDB.iterator();
|
||||||
|
try {
|
||||||
|
if (!iterator.hasNext()) {
|
||||||
|
logger.info("DB is empty - adding Genesis");
|
||||||
|
blockchain.storeBlock(Genesis.getInstance());
|
||||||
|
logger.debug("Block #{} -> {}", Genesis.NUMBER, blockchain.getLastBlock().toFlatString());
|
||||||
|
} else {
|
||||||
|
logger.debug("Displaying blocks stored in DB sorted on blocknumber");
|
||||||
|
|
||||||
|
for (iterator.seekToFirst(); iterator.hasNext();) {
|
||||||
|
Block block = new Block(iterator.next().getValue());
|
||||||
|
blockchain.getBlockCache().put(block.getNumber(), block.getHash());
|
||||||
|
blockchain.setLastBlock(block);
|
||||||
|
logger.debug("Block #{} -> {}", block.getNumber(), block.toFlatString());
|
||||||
|
}
|
||||||
|
logger.info(
|
||||||
|
"*** Loaded up to block [ {} ] with stateRoot [ {} ]",
|
||||||
|
blockchain.getLastBlock().getNumber(), Hex
|
||||||
|
.toHexString(blockchain.getLastBlock()
|
||||||
|
.getStateRoot()));
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
// Make sure you close the iterator to avoid resource leaks.
|
||||||
|
try {
|
||||||
|
iterator.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
logger.error(e.getMessage(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Update world state to latest loaded block from db
|
||||||
|
this.worldState.setRoot(blockchain.getLastBlock().getStateRoot());
|
||||||
|
return blockchain;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public AccountState createAccount(byte[] addr) {
|
public AccountState createAccount(byte[] addr) {
|
||||||
|
|
||||||
this.validateAddress(addr);
|
this.validateAddress(addr);
|
||||||
|
|
||||||
// 1. Save AccountState
|
// 1. Save AccountState
|
||||||
AccountState state = new AccountState();
|
AccountState state = new AccountState();
|
||||||
accountStateDB.update(addr, state.getEncoded());
|
accountStateDB.update(addr, state.getEncoded());
|
||||||
|
@ -109,8 +165,8 @@ public class Repository {
|
||||||
ContractDetails details = new ContractDetails();
|
ContractDetails details = new ContractDetails();
|
||||||
contractDetailsDB.put(addr, details.getEncoded());
|
contractDetailsDB.put(addr, details.getEncoded());
|
||||||
|
|
||||||
if (logger.isInfoEnabled())
|
if (logger.isDebugEnabled())
|
||||||
logger.info("New account created: [ {} ]", Hex.toHexString(addr));
|
logger.debug("New account created: [ {} ]", Hex.toHexString(addr));
|
||||||
|
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
|
@ -122,12 +178,10 @@ public class Repository {
|
||||||
public AccountState getAccountState(byte[] addr) {
|
public AccountState getAccountState(byte[] addr) {
|
||||||
|
|
||||||
this.validateAddress(addr);
|
this.validateAddress(addr);
|
||||||
|
|
||||||
byte[] accountStateRLP = accountStateDB.get(addr);
|
byte[] accountStateRLP = accountStateDB.get(addr);
|
||||||
|
|
||||||
if (accountStateRLP.length == 0) {
|
if (accountStateRLP.length == 0) {
|
||||||
if (logger.isInfoEnabled())
|
|
||||||
logger.info("No account: [ {} ]", Hex.toHexString(addr));
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
AccountState state = new AccountState(accountStateRLP);
|
AccountState state = new AccountState(accountStateRLP);
|
||||||
|
@ -138,18 +192,17 @@ public class Repository {
|
||||||
|
|
||||||
this.validateAddress(addr);
|
this.validateAddress(addr);
|
||||||
|
|
||||||
if (logger.isInfoEnabled())
|
if (logger.isDebugEnabled())
|
||||||
logger.info("Account: [ {} ]", Hex.toHexString(addr));
|
logger.debug("Get contract details for: [ {} ]", Hex.toHexString(addr));
|
||||||
|
|
||||||
byte[] accountDetailsRLP = contractDetailsDB.get(addr);
|
byte[] accountDetailsRLP = contractDetailsDB.get(addr);
|
||||||
|
|
||||||
|
|
||||||
if (accountDetailsRLP == null) {
|
if (accountDetailsRLP == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (logger.isInfoEnabled())
|
if (logger.isDebugEnabled())
|
||||||
logger.info("Contract details RLP: [ {} ]", Hex.toHexString(accountDetailsRLP));
|
logger.debug("Contract details RLP: [ {} ]", Hex.toHexString(accountDetailsRLP));
|
||||||
|
|
||||||
ContractDetails details = new ContractDetails(accountDetailsRLP);
|
ContractDetails details = new ContractDetails(accountDetailsRLP);
|
||||||
return details;
|
return details;
|
||||||
|
@ -167,8 +220,8 @@ public class Repository {
|
||||||
|
|
||||||
BigInteger newBalance = state.addToBalance(value);
|
BigInteger newBalance = state.addToBalance(value);
|
||||||
|
|
||||||
if (logger.isInfoEnabled())
|
if (logger.isDebugEnabled())
|
||||||
logger.info("Changing balance: account: [ {} ] new balance: [ {} ] delta: [ {} ]",
|
logger.debug("Changing balance: account: [ {} ] new balance: [ {} ] delta: [ {} ]",
|
||||||
Hex.toHexString(addr), newBalance.toString(), value);
|
Hex.toHexString(addr), newBalance.toString(), value);
|
||||||
|
|
||||||
accountStateDB.update(addr, state.getEncoded());
|
accountStateDB.update(addr, state.getEncoded());
|
||||||
|
@ -197,8 +250,8 @@ public class Repository {
|
||||||
if (state == null) return BigInteger.ZERO;
|
if (state == null) return BigInteger.ZERO;
|
||||||
state.incrementNonce();
|
state.incrementNonce();
|
||||||
|
|
||||||
if (logger.isInfoEnabled())
|
if (logger.isDebugEnabled())
|
||||||
logger.info("Incerement nonce: account: [ {} ] new nonce: [ {} ]",
|
logger.debug("Incerement nonce: account: [ {} ] new nonce: [ {} ]",
|
||||||
Hex.toHexString(addr), state.getNonce().longValue());
|
Hex.toHexString(addr), state.getNonce().longValue());
|
||||||
|
|
||||||
accountStateDB.update(addr, state.getEncoded());
|
accountStateDB.update(addr, state.getEncoded());
|
||||||
|
@ -219,8 +272,8 @@ public class Repository {
|
||||||
byte[] storageHash = details.getStorageHash();
|
byte[] storageHash = details.getStorageHash();
|
||||||
state.setStateRoot(storageHash);
|
state.setStateRoot(storageHash);
|
||||||
|
|
||||||
if (logger.isInfoEnabled())
|
if (logger.isDebugEnabled())
|
||||||
logger.info("Storage key/value saved: account: [ {} ]\n key: [ {} ] value: [ {} ]\n new storageHash: [ {} ]",
|
logger.debug("Storage key/value saved: account: [ {} ]\n key: [ {} ] value: [ {} ]\n new storageHash: [ {} ]",
|
||||||
Hex.toHexString(addr),
|
Hex.toHexString(addr),
|
||||||
Hex.toHexString(key.getNoLeadZeroesData()),
|
Hex.toHexString(key.getNoLeadZeroesData()),
|
||||||
Hex.toHexString(value.getNoLeadZeroesData()),
|
Hex.toHexString(value.getNoLeadZeroesData()),
|
||||||
|
@ -272,8 +325,8 @@ public class Repository {
|
||||||
byte[] codeHash = HashUtil.sha3(code);
|
byte[] codeHash = HashUtil.sha3(code);
|
||||||
state.setCodeHash(codeHash);
|
state.setCodeHash(codeHash);
|
||||||
|
|
||||||
if (logger.isInfoEnabled())
|
if (logger.isDebugEnabled())
|
||||||
logger.info("Program code saved:\n account: [ {} ]\n codeHash: [ {} ] \n code: [ {} ]",
|
logger.debug("Program code saved:\n account: [ {} ]\n codeHash: [ {} ] \n code: [ {} ]",
|
||||||
Hex.toHexString(addr),
|
Hex.toHexString(addr),
|
||||||
Hex.toHexString(codeHash),
|
Hex.toHexString(codeHash),
|
||||||
Hex.toHexString(code));
|
Hex.toHexString(code));
|
||||||
|
@ -302,7 +355,7 @@ public class Repository {
|
||||||
return stateDB.dumpKeys();
|
return stateDB.dumpKeys();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void dumpState(long blockNumber, int txNumber, String txHash) {
|
public void dumpState(long blockNumber, int txNumber, byte[] txHash) {
|
||||||
|
|
||||||
if (!CONFIG.dumpFull()) return;
|
if (!CONFIG.dumpFull()) return;
|
||||||
|
|
||||||
|
@ -318,7 +371,7 @@ public class Repository {
|
||||||
String fileName = "";
|
String fileName = "";
|
||||||
if (txHash != null)
|
if (txHash != null)
|
||||||
fileName = String.format("%d_%d_%s.dmp",
|
fileName = String.format("%d_%d_%s.dmp",
|
||||||
blockNumber, txNumber, txHash.substring(0, 8));
|
blockNumber, txNumber, Hex.toHexString(txHash).substring(0, 8));
|
||||||
else
|
else
|
||||||
fileName = String.format("%d_c.dmp", blockNumber);
|
fileName = String.format("%d_c.dmp", blockNumber);
|
||||||
|
|
||||||
|
@ -381,6 +434,8 @@ public class Repository {
|
||||||
worldState.sync();
|
worldState.sync();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this.chainDB != null)
|
||||||
|
chainDB.close();
|
||||||
if (this.stateDB != null)
|
if (this.stateDB != null)
|
||||||
stateDB.close();
|
stateDB.close();
|
||||||
if (this.detailsDB != null)
|
if (this.detailsDB != null)
|
||||||
|
|
|
@ -85,13 +85,13 @@ public class EthereumImpl implements Ethereum {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Block getBlockByIndex(long index){
|
public Block getBlockByIndex(long index){
|
||||||
Block block = WorldManager.getInstance().getBlockChain().getByNumber(index);
|
Block block = WorldManager.getInstance().getBlockchain().getByNumber(index);
|
||||||
return block;
|
return block;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public long getBlockChainSize(){
|
public long getBlockChainSize(){
|
||||||
return WorldManager.getInstance().getBlockChain().getSize();
|
return WorldManager.getInstance().getBlockchain().getSize();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -74,9 +74,9 @@ public class BlockChainTable extends JFrame {
|
||||||
@Override
|
@Override
|
||||||
public void actionPerformed(ActionEvent e) {
|
public void actionPerformed(ActionEvent e) {
|
||||||
|
|
||||||
if (WorldManager.getInstance().getBlockChain().getSize() - 1 < lastFindIndex) return;
|
if (WorldManager.getInstance().getBlockchain().getSize() - 1 < lastFindIndex) return;
|
||||||
|
|
||||||
Block block = WorldManager.getInstance().getBlockChain().getByNumber(lastFindIndex);
|
Block block = WorldManager.getInstance().getBlockchain().getByNumber(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);
|
||||||
|
@ -96,10 +96,10 @@ public class BlockChainTable extends JFrame {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = lastFindIndex + 1; i < WorldManager.getInstance().getBlockChain().getSize(); ++i) {
|
for (int i = lastFindIndex + 1; i < WorldManager.getInstance().getBlockchain().getSize(); ++i) {
|
||||||
|
|
||||||
if (WorldManager.getInstance().getBlockChain().getSize() - 1 < i) return;
|
if (WorldManager.getInstance().getBlockchain().getSize() - 1 < i) return;
|
||||||
Block block = WorldManager.getInstance().getBlockChain().getByNumber(i);
|
Block block = WorldManager.getInstance().getBlockchain().getByNumber(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
|
||||||
|
|
|
@ -16,7 +16,7 @@ public class BlockTableModel extends AbstractTableModel {
|
||||||
public int getRowCount() {
|
public int getRowCount() {
|
||||||
|
|
||||||
fireTableDataChanged();
|
fireTableDataChanged();
|
||||||
int rowCount = WorldManager.getInstance().getBlockChain().getSize();
|
int rowCount = WorldManager.getInstance().getBlockchain().getSize();
|
||||||
return rowCount;
|
return rowCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -31,7 +31,7 @@ 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);
|
||||||
|
|
||||||
Block block = WorldManager.getInstance().getBlockChain().getByNumber(rowIndex);
|
Block block = WorldManager.getInstance().getBlockchain().getByNumber(rowIndex);
|
||||||
if (block == null) return "";
|
if (block == null) return "";
|
||||||
|
|
||||||
return block.toString();
|
return block.toString();
|
||||||
|
|
|
@ -315,7 +315,7 @@ class ContractCallDialog extends JDialog implements MessageAwareDialog {
|
||||||
Transaction tx = createTransaction();
|
Transaction tx = createTransaction();
|
||||||
if (tx == null) return;
|
if (tx == null) return;
|
||||||
|
|
||||||
ProgramPlayDialog.createAndShowGUI(programCode, tx, WorldManager.getInstance().getBlockChain().getLastBlock());
|
ProgramPlayDialog.createAndShowGUI(programCode, tx, WorldManager.getInstance().getBlockchain().getLastBlock());
|
||||||
}
|
}
|
||||||
|
|
||||||
protected JRootPane createRootPane() {
|
protected JRootPane createRootPane() {
|
||||||
|
|
|
@ -107,7 +107,7 @@ class ContractSubmitDialog extends JDialog implements MessageAwareDialog {
|
||||||
contractAddrInput.setText(Hex.toHexString(tx.getContractAddress()));
|
contractAddrInput.setText(Hex.toHexString(tx.getContractAddress()));
|
||||||
|
|
||||||
ProgramPlayDialog.createAndShowGUI(tx.getData(), tx,
|
ProgramPlayDialog.createAndShowGUI(tx.getData(), tx,
|
||||||
WorldManager.getInstance().getBlockChain().getLastBlock());
|
WorldManager.getInstance().getBlockchain().getLastBlock());
|
||||||
}}
|
}}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -301,7 +301,7 @@ class ContractSubmitDialog extends JDialog implements MessageAwareDialog {
|
||||||
|
|
||||||
Account account = ((AccountWrapper)creatorAddressCombo.getSelectedItem()).getAccount();
|
Account account = ((AccountWrapper)creatorAddressCombo.getSelectedItem()).getAccount();
|
||||||
BigInteger currentBalance = account.getBalance();
|
BigInteger currentBalance = account.getBalance();
|
||||||
BigInteger gasPrice = BigInteger.valueOf(WorldManager.getInstance().getBlockChain().getGasPrice());
|
BigInteger gasPrice = BigInteger.valueOf(WorldManager.getInstance().getBlockchain().getGasPrice());
|
||||||
BigInteger gasInput = new BigInteger( this.gasInput.getText());
|
BigInteger gasInput = new BigInteger( this.gasInput.getText());
|
||||||
|
|
||||||
boolean canAfford = currentBalance.compareTo(gasPrice.multiply(gasInput)) >= 0;
|
boolean canAfford = currentBalance.compareTo(gasPrice.multiply(gasInput)) >= 0;
|
||||||
|
|
|
@ -118,7 +118,7 @@ class PayOutDialog extends JDialog implements MessageAwareDialog {
|
||||||
byte[] senderPrivKey = account.getEcKey().getPrivKeyBytes();
|
byte[] senderPrivKey = account.getEcKey().getPrivKeyBytes();
|
||||||
byte[] nonce = accountState.getNonce() == BigInteger.ZERO ? null : accountState.getNonce().toByteArray();
|
byte[] nonce = accountState.getNonce() == BigInteger.ZERO ? null : accountState.getNonce().toByteArray();
|
||||||
|
|
||||||
byte[] gasPrice = BigInteger.valueOf( WorldManager.getInstance().getBlockChain().getGasPrice()).toByteArray();
|
byte[] gasPrice = BigInteger.valueOf( WorldManager.getInstance().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
|
||||||
|
@ -193,7 +193,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(WorldManager.getInstance().getBlockChain().getGasPrice());
|
BigInteger gasPrice = BigInteger.valueOf(WorldManager.getInstance().getBlockchain().getGasPrice());
|
||||||
BigInteger currentBalance = accountState.getBalance();
|
BigInteger currentBalance = accountState.getBalance();
|
||||||
|
|
||||||
boolean canAfford = gasPrice.multiply(feeValue).add(ammountValue).compareTo(currentBalance) != 1;
|
boolean canAfford = gasPrice.multiply(feeValue).add(ammountValue).compareTo(currentBalance) != 1;
|
||||||
|
|
|
@ -6,6 +6,7 @@ import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import javax.swing.*;
|
import javax.swing.*;
|
||||||
|
|
||||||
import java.awt.*;
|
import java.awt.*;
|
||||||
import java.awt.event.ItemEvent;
|
import java.awt.event.ItemEvent;
|
||||||
import java.awt.event.ItemListener;
|
import java.awt.event.ItemListener;
|
||||||
|
@ -225,7 +226,7 @@ public class ToolBar extends JFrame {
|
||||||
cp.add(chainToggle);
|
cp.add(chainToggle);
|
||||||
cp.add(walletToggle);
|
cp.add(walletToggle);
|
||||||
|
|
||||||
WorldManager.getInstance();
|
WorldManager.getInstance().loadBlockchain();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void main(String args[]) {
|
public static void main(String args[]) {
|
||||||
|
|
|
@ -8,7 +8,6 @@ import java.net.UnknownHostException;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
import org.ethereum.core.AccountState;
|
import org.ethereum.core.AccountState;
|
||||||
import org.ethereum.core.Block;
|
|
||||||
import org.ethereum.core.Blockchain;
|
import org.ethereum.core.Blockchain;
|
||||||
import org.ethereum.core.Transaction;
|
import org.ethereum.core.Transaction;
|
||||||
import org.ethereum.core.Wallet;
|
import org.ethereum.core.Wallet;
|
||||||
|
@ -16,12 +15,10 @@ import org.ethereum.crypto.ECKey;
|
||||||
import org.ethereum.crypto.HashUtil;
|
import org.ethereum.crypto.HashUtil;
|
||||||
import org.ethereum.db.Repository;
|
import org.ethereum.db.Repository;
|
||||||
import org.ethereum.listener.EthereumListener;
|
import org.ethereum.listener.EthereumListener;
|
||||||
import org.ethereum.net.BlockQueue;
|
|
||||||
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.peerdiscovery.PeerDiscovery;
|
import org.ethereum.net.peerdiscovery.PeerDiscovery;
|
||||||
import org.ethereum.net.submit.WalletTransaction;
|
import org.ethereum.net.submit.WalletTransaction;
|
||||||
import org.ethereum.vm.*;
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.spongycastle.util.encoders.Hex;
|
import org.spongycastle.util.encoders.Hex;
|
||||||
|
@ -37,7 +34,6 @@ import org.spongycastle.util.encoders.Hex;
|
||||||
public class WorldManager {
|
public class WorldManager {
|
||||||
|
|
||||||
private Logger logger = LoggerFactory.getLogger("main");
|
private Logger logger = LoggerFactory.getLogger("main");
|
||||||
private Logger stateLogger = LoggerFactory.getLogger("state");
|
|
||||||
|
|
||||||
private Blockchain blockchain;
|
private Blockchain blockchain;
|
||||||
private Repository repository;
|
private Repository repository;
|
||||||
|
@ -47,9 +43,6 @@ public class WorldManager {
|
||||||
private List<PeerData> peers = Collections.synchronizedList(new ArrayList<PeerData>());
|
private List<PeerData> peers = Collections.synchronizedList(new ArrayList<PeerData>());
|
||||||
private ClientPeer activePeer;
|
private ClientPeer activePeer;
|
||||||
|
|
||||||
private Map<String, Transaction> pendingTransactions = Collections
|
|
||||||
.synchronizedMap(new HashMap<String, Transaction>());
|
|
||||||
|
|
||||||
// This map of transaction designed
|
// This map of transaction designed
|
||||||
// to approve the tx by external trusted peer
|
// to approve the tx by external trusted peer
|
||||||
private Map<String, WalletTransaction> walletTransactions =
|
private Map<String, WalletTransaction> walletTransactions =
|
||||||
|
@ -59,12 +52,10 @@ public class WorldManager {
|
||||||
|
|
||||||
private static WorldManager instance;
|
private static WorldManager instance;
|
||||||
|
|
||||||
private BlockQueue blockQueue = new BlockQueue();
|
private WorldManager() {
|
||||||
|
|
||||||
public WorldManager() {
|
|
||||||
this.blockchain = new Blockchain();
|
|
||||||
this.repository = new Repository();
|
this.repository = new Repository();
|
||||||
|
this.blockchain = new Blockchain(repository);
|
||||||
|
|
||||||
// Initialize PeerData
|
// Initialize PeerData
|
||||||
try {
|
try {
|
||||||
InetAddress ip = InetAddress.getByName(CONFIG.peerDiscoveryIP());
|
InetAddress ip = InetAddress.getByName(CONFIG.peerDiscoveryIP());
|
||||||
|
@ -94,246 +85,9 @@ public class WorldManager {
|
||||||
public static WorldManager getInstance() {
|
public static WorldManager getInstance() {
|
||||||
if(instance == null) {
|
if(instance == null) {
|
||||||
instance = new WorldManager();
|
instance = new WorldManager();
|
||||||
instance.blockchain.load();
|
|
||||||
}
|
}
|
||||||
return instance;
|
return instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void applyTransaction(Block block, Transaction tx, byte[] coinbase) {
|
|
||||||
|
|
||||||
byte[] senderAddress = tx.getSender();
|
|
||||||
AccountState senderAccount = repository.getAccountState(senderAddress);
|
|
||||||
|
|
||||||
if (senderAccount == null) {
|
|
||||||
if (stateLogger.isWarnEnabled())
|
|
||||||
stateLogger.warn("No such address: {}",
|
|
||||||
Hex.toHexString(senderAddress));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 1. VALIDATE THE NONCE
|
|
||||||
BigInteger nonce = senderAccount.getNonce();
|
|
||||||
BigInteger txNonce = new BigInteger(1, tx.getNonce());
|
|
||||||
if (nonce.compareTo(txNonce) != 0) {
|
|
||||||
if (stateLogger.isWarnEnabled())
|
|
||||||
stateLogger.warn("Invalid nonce account.nonce={} tx.nonce={}",
|
|
||||||
nonce, txNonce);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 3. FIND OUT THE TRANSACTION TYPE
|
|
||||||
byte[] receiverAddress, code = null;
|
|
||||||
boolean isContractCreation = tx.isContractCreation();
|
|
||||||
if (isContractCreation) {
|
|
||||||
receiverAddress = tx.getContractAddress();
|
|
||||||
repository.createAccount(receiverAddress);
|
|
||||||
stateLogger.info("New contract created address={}",
|
|
||||||
Hex.toHexString(receiverAddress));
|
|
||||||
code = tx.getData(); // init code
|
|
||||||
if (logger.isInfoEnabled())
|
|
||||||
logger.info("running the init for contract: address={}",
|
|
||||||
Hex.toHexString(receiverAddress));
|
|
||||||
} else {
|
|
||||||
receiverAddress = tx.getReceiveAddress();
|
|
||||||
AccountState receiverState = repository.getAccountState(receiverAddress);
|
|
||||||
if (receiverState == null) {
|
|
||||||
repository.createAccount(receiverAddress);
|
|
||||||
if (stateLogger.isInfoEnabled())
|
|
||||||
stateLogger.info("New receiver account created address={}",
|
|
||||||
Hex.toHexString(receiverAddress));
|
|
||||||
} else {
|
|
||||||
code = repository.getCode(receiverAddress);
|
|
||||||
if (code != null) {
|
|
||||||
if (logger.isInfoEnabled())
|
|
||||||
logger.info("calling for existing contract: address={}",
|
|
||||||
Hex.toHexString(receiverAddress));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 2.1 UPDATE THE NONCE
|
|
||||||
// (THIS STAGE IS NOT REVERTED BY ANY EXCEPTION)
|
|
||||||
repository.increaseNonce(senderAddress);
|
|
||||||
|
|
||||||
// 2.2 PERFORM THE GAS VALUE TX
|
|
||||||
// (THIS STAGE IS NOT REVERTED BY ANY EXCEPTION)
|
|
||||||
BigInteger gasDebit = tx.getTotalGasValueDebit();
|
|
||||||
|
|
||||||
// Debit the actual total gas value from the sender
|
|
||||||
// the purchased gas will be available for
|
|
||||||
// the contract in the execution state,
|
|
||||||
// it can be retrieved using GAS op
|
|
||||||
if (gasDebit.signum() == 1) {
|
|
||||||
BigInteger balance = senderAccount.getBalance();
|
|
||||||
if (balance.compareTo(gasDebit) == -1) {
|
|
||||||
logger.info("No gas to start the execution: sender={}",
|
|
||||||
Hex.toHexString(senderAddress));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
repository.addBalance(senderAddress, gasDebit.negate());
|
|
||||||
|
|
||||||
// The coinbase get the gas cost
|
|
||||||
if (coinbase != null)
|
|
||||||
repository.addBalance(coinbase, gasDebit);
|
|
||||||
|
|
||||||
|
|
||||||
if (stateLogger.isInfoEnabled())
|
|
||||||
stateLogger.info(
|
|
||||||
"Before contract execution debit the sender address with gas total cost, "
|
|
||||||
+ "\n sender={} \n gas_debit= {}",
|
|
||||||
Hex.toHexString(senderAddress), gasDebit);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 3. START TRACKING FOR REVERT CHANGES OPTION !!!
|
|
||||||
Repository trackRepository = repository.getTrack();
|
|
||||||
trackRepository.startTracking();
|
|
||||||
|
|
||||||
try {
|
|
||||||
|
|
||||||
// 4. THE SIMPLE VALUE/BALANCE CHANGE
|
|
||||||
if (tx.getValue() != null) {
|
|
||||||
|
|
||||||
BigInteger senderBalance = senderAccount.getBalance();
|
|
||||||
|
|
||||||
if (senderBalance.compareTo(new BigInteger(1, tx.getValue())) >= 0) {
|
|
||||||
repository.addBalance(receiverAddress,
|
|
||||||
new BigInteger(1, tx.getValue()));
|
|
||||||
repository.addBalance(senderAddress,
|
|
||||||
new BigInteger(1, tx.getValue()).negate());
|
|
||||||
|
|
||||||
if (stateLogger.isInfoEnabled())
|
|
||||||
stateLogger.info("Update value balance \n "
|
|
||||||
+ "sender={}, receiver={}, value={}",
|
|
||||||
Hex.toHexString(senderAddress),
|
|
||||||
Hex.toHexString(receiverAddress),
|
|
||||||
new BigInteger(tx.getValue()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 5. CREATE OR EXECUTE PROGRAM
|
|
||||||
if (isContractCreation || code != null) {
|
|
||||||
Block currBlock = (block == null) ? blockchain.getLastBlock() : block;
|
|
||||||
|
|
||||||
ProgramInvoke programInvoke = ProgramInvokeFactory
|
|
||||||
.createProgramInvoke(tx, currBlock, trackRepository);
|
|
||||||
|
|
||||||
VM vm = new VM();
|
|
||||||
Program program = new Program(code, programInvoke);
|
|
||||||
|
|
||||||
if (CONFIG.playVM())
|
|
||||||
vm.play(program);
|
|
||||||
ProgramResult result = program.getResult();
|
|
||||||
applyProgramResult(result, gasDebit, trackRepository,
|
|
||||||
senderAddress, receiverAddress, coinbase, isContractCreation);
|
|
||||||
} else {
|
|
||||||
// refund everything except fee (500 + 5*txdata)
|
|
||||||
BigInteger gasPrice = new BigInteger(1, tx.getGasPrice());
|
|
||||||
long dataFee = tx.getData() == null ? 0: tx.getData().length * GasCost.TXDATA;
|
|
||||||
long minTxFee = GasCost.TRANSACTION + dataFee;
|
|
||||||
BigInteger refund = gasDebit.subtract(BigInteger.valueOf(
|
|
||||||
minTxFee).multiply(gasPrice));
|
|
||||||
if (refund.signum() > 0) {
|
|
||||||
// gas refund
|
|
||||||
repository.addBalance(senderAddress, refund);
|
|
||||||
repository.addBalance(coinbase, refund.negate());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (RuntimeException e) {
|
|
||||||
trackRepository.rollback();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
trackRepository.commit();
|
|
||||||
pendingTransactions.put(Hex.toHexString(tx.getHash()), tx);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* After any contract code finish the run the certain result should take
|
|
||||||
* place, according the given circumstances
|
|
||||||
*
|
|
||||||
* @param result
|
|
||||||
* @param gasDebit
|
|
||||||
* @param senderAddress
|
|
||||||
* @param contractAddress
|
|
||||||
*/
|
|
||||||
private void applyProgramResult(ProgramResult result, BigInteger gasDebit,
|
|
||||||
Repository repository, byte[] senderAddress,
|
|
||||||
byte[] contractAddress, byte[] coinbase, boolean initResults) {
|
|
||||||
|
|
||||||
if (result.getException() != null
|
|
||||||
&& result.getException() instanceof Program.OutOfGasException) {
|
|
||||||
logger.info("contract run halted by OutOfGas: contract={}",
|
|
||||||
Hex.toHexString(contractAddress));
|
|
||||||
throw result.getException();
|
|
||||||
}
|
|
||||||
|
|
||||||
BigInteger gasPrice = BigInteger.valueOf(blockchain.getGasPrice());
|
|
||||||
BigInteger refund = gasDebit.subtract(BigInteger.valueOf(
|
|
||||||
result.getGasUsed()).multiply(gasPrice));
|
|
||||||
|
|
||||||
if (refund.signum() > 0) {
|
|
||||||
if (stateLogger.isInfoEnabled())
|
|
||||||
stateLogger
|
|
||||||
.info("After contract execution the sender address refunded with gas leftover, "
|
|
||||||
+ "\n sender={} \n contract={} \n gas_refund= {}",
|
|
||||||
Hex.toHexString(senderAddress),
|
|
||||||
Hex.toHexString(contractAddress), refund);
|
|
||||||
// gas refund
|
|
||||||
repository.addBalance(senderAddress, refund);
|
|
||||||
repository.addBalance(coinbase, refund.negate());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (initResults) {
|
|
||||||
// Save the code created by init
|
|
||||||
byte[] bodyCode = null;
|
|
||||||
if (result.getHReturn() != null) {
|
|
||||||
bodyCode = result.getHReturn().array();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (bodyCode != null) {
|
|
||||||
repository.saveCode(contractAddress, bodyCode);
|
|
||||||
if (stateLogger.isInfoEnabled())
|
|
||||||
stateLogger
|
|
||||||
.info("saving code of the contract to the db:\n contract={} code={}",
|
|
||||||
Hex.toHexString(contractAddress),
|
|
||||||
Hex.toHexString(bodyCode));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// delete the marked to die accounts
|
|
||||||
if (result.getDeleteAccounts() == null) return;
|
|
||||||
for (DataWord address : result.getDeleteAccounts()){
|
|
||||||
repository.delete(address.getNoLeadZeroesData());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void applyBlock(Block block) {
|
|
||||||
|
|
||||||
if(block.getNumber() == 1157) {
|
|
||||||
logger.debug("Block 1157");
|
|
||||||
}
|
|
||||||
|
|
||||||
int i = 0;
|
|
||||||
for (Transaction tx : block.getTransactionsList()) {
|
|
||||||
logger.info("apply block: [ {} ] tx: [ {} ] ", block.getNumber(), i);
|
|
||||||
applyTransaction(block, tx, block.getCoinbase());
|
|
||||||
repository.dumpState(block.getNumber(), i,
|
|
||||||
Hex.toHexString(tx.getHash()));
|
|
||||||
++i;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// miner reward
|
|
||||||
if (repository.getAccountState(block.getCoinbase()) == null)
|
|
||||||
repository.createAccount(block.getCoinbase());
|
|
||||||
repository.addBalance(block.getCoinbase(), Block.BLOCK_REWARD);
|
|
||||||
for (Block uncle : block.getUncleList()) {
|
|
||||||
repository.addBalance(uncle.getCoinbase(), Block.UNCLE_REWARD);
|
|
||||||
}
|
|
||||||
|
|
||||||
repository.dumpState(block.getNumber(), 0,
|
|
||||||
null);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/***********************************************************************
|
/***********************************************************************
|
||||||
* 1) the dialog put a pending transaction on the list
|
* 1) the dialog put a pending transaction on the list
|
||||||
|
@ -361,6 +115,14 @@ public class WorldManager {
|
||||||
logger.info("pending transaction removed with hash: {} ", hash);
|
logger.info("pending transaction removed with hash: {} ", hash);
|
||||||
walletTransactions.remove(hash);
|
walletTransactions.remove(hash);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setRepository(Repository repository) {
|
||||||
|
this.repository = repository;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setBlockchain(Blockchain blockchain) {
|
||||||
|
this.blockchain = blockchain;
|
||||||
|
}
|
||||||
|
|
||||||
public void setWallet(Wallet wallet) {
|
public void setWallet(Wallet wallet) {
|
||||||
this.wallet = wallet;
|
this.wallet = wallet;
|
||||||
|
@ -370,9 +132,13 @@ public class WorldManager {
|
||||||
return repository;
|
return repository;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Blockchain getBlockChain() {
|
public Blockchain getBlockchain() {
|
||||||
return blockchain;
|
return blockchain;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void loadBlockchain() {
|
||||||
|
this.blockchain = repository.loadBlockchain();
|
||||||
|
}
|
||||||
|
|
||||||
public Wallet getWallet() {
|
public Wallet getWallet() {
|
||||||
return wallet;
|
return wallet;
|
||||||
|
@ -394,7 +160,6 @@ public class WorldManager {
|
||||||
this.listener = listener;
|
this.listener = listener;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void addPeers(List<PeerData> newPeers) {
|
public void addPeers(List<PeerData> newPeers) {
|
||||||
for (PeerData peer : newPeers) {
|
for (PeerData peer : newPeers) {
|
||||||
if (this.peers.indexOf(peer) == -1) {
|
if (this.peers.indexOf(peer) == -1) {
|
||||||
|
@ -420,12 +185,7 @@ public class WorldManager {
|
||||||
peerDiscovery.stop();
|
peerDiscovery.stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
public BlockQueue getBlockQueue() {
|
|
||||||
return blockQueue;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void close() {
|
public void close() {
|
||||||
blockchain.close();
|
|
||||||
repository.close();
|
repository.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -20,10 +20,10 @@ public class BlockQueue {
|
||||||
|
|
||||||
private static Logger logger = LoggerFactory.getLogger("blockchain");
|
private static Logger logger = LoggerFactory.getLogger("blockchain");
|
||||||
|
|
||||||
ConcurrentLinkedQueue<Block> blockQueue = new ConcurrentLinkedQueue<Block>();
|
private Queue<Block> blockQueue = new ConcurrentLinkedQueue<>();
|
||||||
Block lastBlock;
|
private Block lastBlock;
|
||||||
|
|
||||||
Timer timer = new Timer();
|
private Timer timer = new Timer();
|
||||||
|
|
||||||
public BlockQueue() {
|
public BlockQueue() {
|
||||||
|
|
||||||
|
@ -40,7 +40,7 @@ public class BlockQueue {
|
||||||
|
|
||||||
Block block = blockQueue.poll();
|
Block block = blockQueue.poll();
|
||||||
|
|
||||||
WorldManager.getInstance().getBlockChain().add(block);
|
WorldManager.getInstance().getBlockchain().add(block);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addBlocks(List<Block> blockList) {
|
public void addBlocks(List<Block> blockList) {
|
||||||
|
@ -64,7 +64,7 @@ public class BlockQueue {
|
||||||
public Block getLast() {
|
public Block getLast() {
|
||||||
|
|
||||||
if (blockQueue.isEmpty())
|
if (blockQueue.isEmpty())
|
||||||
return WorldManager.getInstance().getBlockChain().getLastBlock();
|
return WorldManager.getInstance().getBlockchain().getLastBlock();
|
||||||
|
|
||||||
return lastBlock;
|
return lastBlock;
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,6 @@ package org.ethereum.net.client;
|
||||||
import io.netty.buffer.ByteBuf;
|
import io.netty.buffer.ByteBuf;
|
||||||
import io.netty.channel.ChannelHandlerContext;
|
import io.netty.channel.ChannelHandlerContext;
|
||||||
import io.netty.handler.codec.ByteToMessageDecoder;
|
import io.netty.handler.codec.ByteToMessageDecoder;
|
||||||
import io.netty.handler.codec.CorruptedFrameException;
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
|
|
@ -183,7 +183,8 @@ public class EthereumProtocolHandler extends ChannelInboundHandlerAdapter {
|
||||||
|
|
||||||
List<Transaction> txList = transactionsMessage.getTransactions();
|
List<Transaction> txList = transactionsMessage.getTransactions();
|
||||||
for(Transaction tx : txList)
|
for(Transaction tx : txList)
|
||||||
WorldManager.getInstance().applyTransaction(null, tx, null);
|
WorldManager.getInstance().getBlockchain()
|
||||||
|
.applyTransaction(null, tx, null);
|
||||||
|
|
||||||
logger.info(transactionsMessage.toString());
|
logger.info(transactionsMessage.toString());
|
||||||
if (peerListener != null) peerListener.console(transactionsMessage.toString());
|
if (peerListener != null) peerListener.console(transactionsMessage.toString());
|
||||||
|
@ -235,7 +236,7 @@ public class EthereumProtocolHandler extends ChannelInboundHandlerAdapter {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (blockList.isEmpty()) return;
|
if (blockList.isEmpty()) return;
|
||||||
WorldManager.getInstance().getBlockQueue().addBlocks(blockList);
|
WorldManager.getInstance().getBlockchain().getBlockQueue().addBlocks(blockList);
|
||||||
if (peerListener != null) peerListener.console(blocksMessage.toString());
|
if (peerListener != null) peerListener.console(blocksMessage.toString());
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -318,10 +319,10 @@ public class EthereumProtocolHandler extends ChannelInboundHandlerAdapter {
|
||||||
|
|
||||||
private void sendGetChain() {
|
private void sendGetChain() {
|
||||||
|
|
||||||
if (WorldManager.getInstance().getBlockQueue().size() >
|
if (WorldManager.getInstance().getBlockchain().getBlockQueue().size() >
|
||||||
SystemProperties.CONFIG.maxBlocksQueued()) return;
|
SystemProperties.CONFIG.maxBlocksQueued()) return;
|
||||||
|
|
||||||
Block lastBlock = WorldManager.getInstance().getBlockQueue().getLast();
|
Block lastBlock = WorldManager.getInstance().getBlockchain().getBlockQueue().getLast();
|
||||||
|
|
||||||
byte[] hash = lastBlock.getHash();
|
byte[] hash = lastBlock.getHash();
|
||||||
GetChainMessage chainMessage =
|
GetChainMessage chainMessage =
|
||||||
|
|
|
@ -88,7 +88,7 @@ public class GetChainMessage extends Message {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Class getAnswerMessage() {
|
public Class<BlocksMessage> getAnswerMessage() {
|
||||||
return BlocksMessage.class;
|
return BlocksMessage.class;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -27,7 +27,7 @@ public class GetPeersMessage extends Message {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Class getAnswerMessage() {
|
public Class<PeersMessage> getAnswerMessage() {
|
||||||
return PeersMessage.class;
|
return PeersMessage.class;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,15 +1,7 @@
|
||||||
package org.ethereum.net.message;
|
package org.ethereum.net.message;
|
||||||
|
|
||||||
import org.ethereum.util.RLP;
|
|
||||||
import org.ethereum.util.RLPItem;
|
|
||||||
import org.ethereum.util.RLPList;
|
|
||||||
import org.spongycastle.util.encoders.Hex;
|
import org.spongycastle.util.encoders.Hex;
|
||||||
|
|
||||||
import java.math.BigInteger;
|
|
||||||
import java.nio.ByteBuffer;
|
|
||||||
|
|
||||||
import static org.ethereum.net.Command.HELLO;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* www.ethereumJ.com
|
* www.ethereumJ.com
|
||||||
* @author: Roman Mandeleil
|
* @author: Roman Mandeleil
|
||||||
|
@ -35,7 +27,7 @@ public class PingMessage extends Message {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Class getAnswerMessage() {
|
public Class<PongMessage> getAnswerMessage() {
|
||||||
return PongMessage.class;
|
return PongMessage.class;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,13 +16,12 @@ import org.iq80.leveldb.DB;
|
||||||
*/
|
*/
|
||||||
public class Cache {
|
public class Cache {
|
||||||
|
|
||||||
private Map<ByteArrayWrapper, Node> nodes;
|
private Map<ByteArrayWrapper, Node> nodes = new HashMap<>();
|
||||||
private DB db;
|
private DB db;
|
||||||
private boolean isDirty;
|
private boolean isDirty;
|
||||||
|
|
||||||
public Cache(DB db) {
|
public Cache(DB db) {
|
||||||
this.db = db;
|
this.db = db;
|
||||||
nodes = new HashMap<ByteArrayWrapper, Node>();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -88,7 +87,7 @@ public class Cache {
|
||||||
// If the nodes grows beyond the 200 entries we simple empty it
|
// If the nodes grows beyond the 200 entries we simple empty it
|
||||||
// FIXME come up with something better
|
// FIXME come up with something better
|
||||||
if (this.nodes.size() > 200) {
|
if (this.nodes.size() > 200) {
|
||||||
this.nodes = new HashMap<ByteArrayWrapper, Node>();
|
this.nodes = new HashMap<>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -72,6 +72,10 @@ public class Trie implements TrieFacade {
|
||||||
return root;
|
return root;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setRoot(Object root) {
|
||||||
|
this.root = root;
|
||||||
|
}
|
||||||
|
|
||||||
public void setCache(Cache cache) {
|
public void setCache(Cache cache) {
|
||||||
this.cache = cache;
|
this.cache = cache;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,7 @@
|
||||||
package org.ethereum.util;
|
package org.ethereum.util;
|
||||||
|
|
||||||
import com.maxmind.geoip.Location;
|
|
||||||
import org.apache.log4j.PropertyConfigurator;
|
import org.apache.log4j.PropertyConfigurator;
|
||||||
import org.ethereum.db.IpGeoDB;
|
|
||||||
|
|
||||||
import java.net.InetAddress;
|
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
|
|
||||||
import static org.ethereum.config.SystemProperties.CONFIG;
|
import static org.ethereum.config.SystemProperties.CONFIG;
|
||||||
|
|
|
@ -24,7 +24,7 @@ public class ProgramInvokeFactory {
|
||||||
public static ProgramInvoke createProgramInvoke(Transaction tx, Block block, Repository repository) {
|
public static ProgramInvoke createProgramInvoke(Transaction tx, Block block, Repository repository) {
|
||||||
|
|
||||||
// https://ethereum.etherpad.mozilla.org/26
|
// https://ethereum.etherpad.mozilla.org/26
|
||||||
Block lastBlock = WorldManager.getInstance().getBlockChain().getLastBlock();
|
Block lastBlock = WorldManager.getInstance().getBlockchain().getLastBlock();
|
||||||
|
|
||||||
/*** ADDRESS op ***/
|
/*** ADDRESS op ***/
|
||||||
// YP: Get address of currently executing account.
|
// YP: Get address of currently executing account.
|
||||||
|
|
|
@ -23,9 +23,9 @@ log4j.logger.io.netty = ERROR
|
||||||
log4j.logger.wire = ERROR
|
log4j.logger.wire = ERROR
|
||||||
log4j.logger.VM = DEBUG
|
log4j.logger.VM = DEBUG
|
||||||
log4j.logger.main = INFO
|
log4j.logger.main = INFO
|
||||||
log4j.logger.state = ERROR
|
log4j.logger.state = DEBUG
|
||||||
log4j.logger.repository = DEBUG
|
log4j.logger.repository = DEBUG
|
||||||
log4j.logger.blockchain = DEBUG
|
log4j.logger.blockchain = INFO
|
||||||
log4j.logger.ui = ERROR
|
log4j.logger.ui = ERROR
|
||||||
log4j.logger.gas = ERROR
|
log4j.logger.gas = ERROR
|
||||||
|
|
||||||
|
|
|
@ -24,8 +24,8 @@ log4j.logger.wire = ERROR
|
||||||
log4j.logger.VM = ERROR
|
log4j.logger.VM = ERROR
|
||||||
log4j.logger.main = ERROR
|
log4j.logger.main = ERROR
|
||||||
log4j.logger.trie = ERROR
|
log4j.logger.trie = ERROR
|
||||||
log4j.logger.state = ERROR
|
log4j.logger.state = INFO
|
||||||
log4j.logger.repository = ERROR
|
log4j.logger.repository = INFO
|
||||||
log4j.logger.blockchain = INFO
|
log4j.logger.blockchain = INFO
|
||||||
log4j.logger.txs = ERROR
|
log4j.logger.txs = ERROR
|
||||||
log4j.logger.ui = ERROR
|
log4j.logger.ui = ERROR
|
||||||
|
|
|
@ -99,7 +99,7 @@ coinbase.secret = "monkey"
|
||||||
# in JSON form to [dump.dir]
|
# in JSON form to [dump.dir]
|
||||||
# if [dump.full] = true
|
# if [dump.full] = true
|
||||||
# posible values [true/false]
|
# posible values [true/false]
|
||||||
dump.full = true
|
dump.full = false
|
||||||
dump.dir = dmp
|
dump.dir = dmp
|
||||||
|
|
||||||
# clean the dump dir each start
|
# clean the dump dir each start
|
||||||
|
|
|
@ -115,7 +115,7 @@ public class BlockTest {
|
||||||
assertEquals(new BigInteger(1, Genesis.DIFFICULTY), difficulty);
|
assertEquals(new BigInteger(1, Genesis.DIFFICULTY), difficulty);
|
||||||
|
|
||||||
// Storing genesis because the parent needs to be in the DB for calculation.
|
// Storing genesis because the parent needs to be in the DB for calculation.
|
||||||
WorldManager.getInstance().getBlockChain().add(genesis);
|
WorldManager.getInstance().getBlockchain().add(genesis);
|
||||||
|
|
||||||
Block block1 = new Block(Hex.decode(block_1));
|
Block block1 = new Block(Hex.decode(block_1));
|
||||||
BigInteger calcDifficulty = new BigInteger(1, block1.calcDifficulty());
|
BigInteger calcDifficulty = new BigInteger(1, block1.calcDifficulty());
|
||||||
|
@ -137,7 +137,7 @@ public class BlockTest {
|
||||||
assertEquals(Genesis.GAS_LIMIT, gasLimit);
|
assertEquals(Genesis.GAS_LIMIT, gasLimit);
|
||||||
|
|
||||||
// Storing genesis because the parent needs to be in the DB for calculation.
|
// Storing genesis because the parent needs to be in the DB for calculation.
|
||||||
WorldManager.getInstance().getBlockChain().add(genesis);
|
WorldManager.getInstance().getBlockchain().add(genesis);
|
||||||
|
|
||||||
// Test with block
|
// Test with block
|
||||||
Block block1 = new Block(Hex.decode(block_1));
|
Block block1 = new Block(Hex.decode(block_1));
|
||||||
|
|
Loading…
Reference in New Issue