Merge pull request #62 from nicksavers/master

Refactoring uncle reward and wallet processing
This commit is contained in:
romanman 2014-07-11 16:51:03 +03:00
commit eb382199cc
4 changed files with 53 additions and 57 deletions

View File

@ -37,6 +37,8 @@ public class Block {
/* A scalar value equal to the mininum limit of gas expenditure per block */ /* A scalar value equal to the mininum limit of gas expenditure per block */
private static long MIN_GAS_LIMIT = 125000L; private static long MIN_GAS_LIMIT = 125000L;
public static BigInteger BLOCK_REWARD = BigInteger.valueOf(1500000000000000000L); public static BigInteger BLOCK_REWARD = BigInteger.valueOf(1500000000000000000L);
public static BigInteger UNCLE_REWARD = BLOCK_REWARD.multiply(
BigInteger.valueOf(7)).divide(BigInteger.valueOf(8));
private BlockHeader header; private BlockHeader header;
@ -91,7 +93,7 @@ public class Block {
// Parse Transactions // Parse Transactions
RLPList txReceipts = (RLPList) block.get(1); RLPList txReceipts = (RLPList) block.get(1);
this.processTxs(txReceipts); this.parseTxs(txReceipts);
// Parse Uncles // Parse Uncles
RLPList uncleBlocks = (RLPList) block.get(2); RLPList uncleBlocks = (RLPList) block.get(2);
@ -259,7 +261,7 @@ public class Block {
return toStringBuff.toString(); return toStringBuff.toString();
} }
private void processTxs(RLPList txReceipts) { private void parseTxs(RLPList txReceipts) {
this.txsState = new Trie(null); this.txsState = new Trie(null);
for (int i = 0; i < txReceipts.size(); i++) { for (int i = 0; i < txReceipts.size(); i++) {

View File

@ -2,7 +2,6 @@ package org.ethereum.core;
import org.ethereum.db.DatabaseImpl; import org.ethereum.db.DatabaseImpl;
import org.ethereum.manager.WorldManager; import org.ethereum.manager.WorldManager;
import org.ethereum.net.submit.WalletTransaction;
import org.ethereum.util.ByteUtil; import org.ethereum.util.ByteUtil;
import org.iq80.leveldb.DBIterator; import org.iq80.leveldb.DBIterator;
import org.slf4j.Logger; import org.slf4j.Logger;
@ -54,7 +53,6 @@ public class Blockchain {
private static long INITIAL_MIN_GAS_PRICE = 10 * SZABO.longValue(); private static long INITIAL_MIN_GAS_PRICE = 10 * SZABO.longValue();
private DatabaseImpl chainDb; private DatabaseImpl chainDb;
private Wallet wallet;
private long gasPrice = 1000; private long gasPrice = 1000;
private Block lastBlock; private Block lastBlock;
@ -63,11 +61,6 @@ public class Blockchain {
// convenient usage, <block_number, block_hash> // convenient usage, <block_number, block_hash>
private Map<Long, byte[]> index = new HashMap<>(); private Map<Long, byte[]> index = new HashMap<>();
// This map of transaction designed
// to approve the tx by external trusted peer
private Map<String, WalletTransaction> walletTransactions =
Collections.synchronizedMap(new HashMap<String, WalletTransaction>());
public Blockchain() { public Blockchain() {
this.chainDb = new DatabaseImpl("blockchain"); this.chainDb = new DatabaseImpl("blockchain");
} }
@ -108,7 +101,7 @@ public class Blockchain {
String blockParentHash = Hex.toHexString(firstBlockToAdd.getParentHash()); String blockParentHash = Hex.toHexString(firstBlockToAdd.getParentHash());
if (!hashLast.equals(blockParentHash)) return; if (!hashLast.equals(blockParentHash)) return;
} }
for (int i = blocks.size() - 1; i >= 0 ; --i) { for (int i = blocks.size() - 1; i >= 0 ; --i) {
this.addBlock(blocks.get(i)); this.addBlock(blocks.get(i));
/* Debug check to see if the state is still as expected */ /* Debug check to see if the state is still as expected */
@ -124,7 +117,7 @@ public class Blockchain {
for (Transaction tx : block.getTransactionsList()) { for (Transaction tx : block.getTransactionsList()) {
if (logger.isDebugEnabled()) if (logger.isDebugEnabled())
logger.debug("pending cleanup: tx.hash: [{}]", Hex.toHexString( tx.getHash())); logger.debug("pending cleanup: tx.hash: [{}]", Hex.toHexString( tx.getHash()));
this.removeWalletTransaction(tx); WorldManager.getInstance().removeWalletTransaction(tx);
} }
} }
logger.info("*** Block chain size: [ {} ]", this.getSize()); logger.info("*** Block chain size: [ {} ]", this.getSize());
@ -133,13 +126,17 @@ public class Blockchain {
public void addBlock(Block block) { public void addBlock(Block block) {
if(block.isValid()) { if(block.isValid()) {
if (!block.isGenesis()) if (!block.isGenesis()) {
for (Transaction tx : block.getTransactionsList())
// TODO: refactor the wallet pending transactions to the world manager
WorldManager.getInstance().addWalletTransaction(tx);
WorldManager.getInstance().applyBlock(block); WorldManager.getInstance().applyBlock(block);
}
this.chainDb.put(ByteUtil.longToBytes(block.getNumber()), block.getEncoded()); this.chainDb.put(ByteUtil.longToBytes(block.getNumber()), block.getEncoded());
this.index.put(block.getNumber(), block.getEncoded()); this.index.put(block.getNumber(), block.getEncoded());
this.wallet.processBlock(block); WorldManager.getInstance().getWallet().processBlock(block);
this.updateGasPrice(block); this.updateGasPrice(block);
this.setLastBlock(block); this.setLastBlock(block);
if (logger.isDebugEnabled()) if (logger.isDebugEnabled())
@ -158,37 +155,6 @@ public class Blockchain {
return gasPrice; return gasPrice;
} }
/***********************************************************************
* 1) the dialog put a pending transaction on the list
* 2) the dialog send the transaction to a net
* 3) wherever the transaction got in from the wire it 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 WalletTransaction addWalletTransaction(Transaction transaction) {
String hash = Hex.toHexString(transaction.getHash());
logger.info("pending transaction placed hash: {}", hash );
WalletTransaction walletTransaction = this.walletTransactions.get(hash);
if (walletTransaction != null)
walletTransaction.incApproved();
else {
walletTransaction = new WalletTransaction(transaction);
this.walletTransactions.put(hash, walletTransaction);
}
return walletTransaction;
}
public void removeWalletTransaction(Transaction transaction) {
String hash = Hex.toHexString(transaction.getHash());
logger.info("pending transaction removed with hash: {} ", hash);
walletTransactions.remove(hash);
}
public void setWallet(Wallet wallet) {
this.wallet = wallet;
}
public byte[] getLatestBlockHash() { public byte[] getLatestBlockHash() {
if (index.isEmpty()) if (index.isEmpty())
return Genesis.getInstance().getHash(); return Genesis.getInstance().getHash();

View File

@ -5,7 +5,6 @@ import static org.ethereum.config.SystemProperties.CONFIG;
import java.math.BigInteger; import java.math.BigInteger;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.List;
import java.util.Map; import java.util.Map;
import org.ethereum.core.AccountState; import org.ethereum.core.AccountState;
@ -16,6 +15,7 @@ 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.db.Repository; import org.ethereum.db.Repository;
import org.ethereum.net.submit.WalletTransaction;
import org.ethereum.vm.*; import org.ethereum.vm.*;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -40,6 +40,11 @@ public class WorldManager {
private Map<String, Transaction> pendingTransactions = Collections private Map<String, Transaction> pendingTransactions = Collections
.synchronizedMap(new HashMap<String, Transaction>()); .synchronizedMap(new HashMap<String, Transaction>());
// This map of transaction designed
// to approve the tx by external trusted peer
private Map<String, WalletTransaction> walletTransactions =
Collections.synchronizedMap(new HashMap<String, WalletTransaction>());
private static WorldManager instance; private static WorldManager instance;
@ -59,8 +64,6 @@ public class WorldManager {
String secret = CONFIG.coinbaseSecret(); String secret = CONFIG.coinbaseSecret();
byte[] cbAddr = HashUtil.sha3(secret.getBytes()); byte[] cbAddr = HashUtil.sha3(secret.getBytes());
wallet.importKey(cbAddr); wallet.importKey(cbAddr);
blockchain.setWallet(wallet);
} }
public static WorldManager getInstance() { public static WorldManager getInstance() {
@ -73,10 +76,6 @@ public class WorldManager {
public void applyTransaction(Transaction tx, byte[] coinbase) { public void applyTransaction(Transaction tx, byte[] coinbase) {
// TODO: refactor the wallet pending transactions to the world manager
if (blockchain != null)
blockchain.addWalletTransaction(tx);
byte[] senderAddress = tx.getSender(); byte[] senderAddress = tx.getSender();
AccountState senderAccount = repository.getAccountState(senderAddress); AccountState senderAccount = repository.getAccountState(senderAddress);
@ -276,12 +275,10 @@ public class WorldManager {
} }
} }
private static BigInteger UNCLE_RATIO = BigInteger.valueOf(7).divide(BigInteger.valueOf(8));
public void applyBlock(Block block) { public void applyBlock(Block block) {
int i = 0; int i = 0;
List<Transaction> txList = block.getTransactionsList(); for (Transaction tx : block.getTransactionsList()) {
for (Transaction tx : txList) {
applyTransaction(tx, block.getCoinbase()); applyTransaction(tx, block.getCoinbase());
repository.dumpState(block.getNumber(), i, repository.dumpState(block.getNumber(), i,
Hex.toHexString(tx.getHash())); Hex.toHexString(tx.getHash()));
@ -293,9 +290,40 @@ public class WorldManager {
repository.createAccount(block.getCoinbase()); repository.createAccount(block.getCoinbase());
repository.addBalance(block.getCoinbase(), Block.BLOCK_REWARD); repository.addBalance(block.getCoinbase(), Block.BLOCK_REWARD);
for (Block uncle : block.getUncleList()) { for (Block uncle : block.getUncleList()) {
repository.addBalance(uncle.getCoinbase(), Block.BLOCK_REWARD.multiply(UNCLE_RATIO)); repository.addBalance(uncle.getCoinbase(), Block.UNCLE_REWARD);
} }
} }
/***********************************************************************
* 1) the dialog put a pending transaction on the list
* 2) the dialog send the transaction to a net
* 3) wherever the transaction got in from the wire it 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 WalletTransaction addWalletTransaction(Transaction transaction) {
String hash = Hex.toHexString(transaction.getHash());
logger.info("pending transaction placed hash: {}", hash );
WalletTransaction walletTransaction = this.walletTransactions.get(hash);
if (walletTransaction != null)
walletTransaction.incApproved();
else {
walletTransaction = new WalletTransaction(transaction);
this.walletTransactions.put(hash, walletTransaction);
}
return walletTransaction;
}
public void removeWalletTransaction(Transaction transaction) {
String hash = Hex.toHexString(transaction.getHash());
logger.info("pending transaction removed with hash: {} ", hash);
walletTransactions.remove(hash);
}
public void setWallet(Wallet wallet) {
this.wallet = wallet;
}
public Repository getRepository() { public Repository getRepository() {
return repository; return repository;

View File

@ -35,7 +35,7 @@ public class TransactionTask implements Callable<Transaction> {
ClientPeer peer = MainData.instance.getActivePeer(); ClientPeer peer = MainData.instance.getActivePeer();
WalletTransaction walletTransaction = WorldManager.getInstance() WalletTransaction walletTransaction = WorldManager.getInstance()
.getBlockChain().addWalletTransaction(tx); .addWalletTransaction(tx);
peer.sendTransaction(tx); peer.sendTransaction(tx);
while(walletTransaction.getApproved() < 1 ) { while(walletTransaction.getApproved() < 1 ) {
@ -44,7 +44,7 @@ public class TransactionTask implements Callable<Transaction> {
logger.info("return approved: {}", walletTransaction.getApproved()); logger.info("return approved: {}", walletTransaction.getApproved());
} catch (Throwable th) { } catch (Throwable th) {
logger.info("exception caugh: {}", th); logger.info("exception caugh: {}", th);
WorldManager.getInstance().getBlockChain().removeWalletTransaction(tx); WorldManager.getInstance().removeWalletTransaction(tx);
} }
return null; return null;
} }