diff --git a/ethereumj-core/src/main/java/org/ethereum/config/SystemProperties.java b/ethereumj-core/src/main/java/org/ethereum/config/SystemProperties.java index f9133d1f..ecdf88ba 100644 --- a/ethereumj-core/src/main/java/org/ethereum/config/SystemProperties.java +++ b/ethereumj-core/src/main/java/org/ethereum/config/SystemProperties.java @@ -24,8 +24,10 @@ public class SystemProperties { private static int DEFAULT_DISCOVERY_PORT = 30303; private static String DEFAULT_ACTIVE_PEER_IP = "54.201.28.117"; private static int DEFAULT_ACTIVE_PORT = 30303; - private static String DEFAULT_SAMPLES_DIR = "samples"; - + private static String DEFAULT_SAMPLES_DIR = "samples"; + private static String DEFAULT_COINBASE_SECRET = "monkey"; + private static int DEFAULT_ACTIVE_PEER_CHANNEL_TIMEOUT = 5; + public static SystemProperties CONFIG = new SystemProperties(); private Properties prop = new Properties(); private InputStream input = null; @@ -117,7 +119,18 @@ public class SystemProperties { return prop.getProperty("samples.dir"); } - public void print() { + public String coinbaseSecret(){ + if(prop.isEmpty()) return DEFAULT_COINBASE_SECRET; + return prop.getProperty("coinbase.secret"); + } + + public Integer activePeerChannelTimeout(){ + if(prop.isEmpty()) return DEFAULT_ACTIVE_PEER_CHANNEL_TIMEOUT; + return Integer.parseInt(prop.getProperty("active.peer.channel.timeout")); + } + + + public void print() { Enumeration e = prop.propertyNames(); while (e.hasMoreElements()) { String key = (String) e.nextElement(); diff --git a/ethereumj-core/src/main/java/org/ethereum/core/AccountState.java b/ethereumj-core/src/main/java/org/ethereum/core/AccountState.java index 35f316be..293787a9 100644 --- a/ethereumj-core/src/main/java/org/ethereum/core/AccountState.java +++ b/ethereumj-core/src/main/java/org/ethereum/core/AccountState.java @@ -13,7 +13,7 @@ public class AccountState { private ECKey ecKey; private byte[] rlpEncoded; - /* A value equal to the number of transactions sent + /* 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; @@ -27,7 +27,7 @@ public class AccountState { * 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, + * but to the underlying set of key/value pairs stored within, * I define a convenient equivalence 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 */ @@ -53,7 +53,8 @@ public class AccountState { this.rlpEncoded = rlpData; RLPList items = (RLPList) RLP.decode2(rlpEncoded).get(0); - this.nonce = new BigInteger(1, ((items.get(0).getRLPData()) == null ? new byte[0] : items.get(0).getRLPData())); + this.nonce = new BigInteger(1, ((items.get(0).getRLPData()) == null ? new byte[]{0} : + items.get(0).getRLPData())); this.balance = new BigInteger(1, items.get(1).getRLPData()); this.stateRoot = items.get(2).getRLPData(); this.codeHash = items.get(3).getRLPData(); diff --git a/ethereumj-core/src/main/java/org/ethereum/core/Block.java b/ethereumj-core/src/main/java/org/ethereum/core/Block.java index f8ce6771..bda7e510 100644 --- a/ethereumj-core/src/main/java/org/ethereum/core/Block.java +++ b/ethereumj-core/src/main/java/org/ethereum/core/Block.java @@ -1,7 +1,7 @@ package org.ethereum.core; import org.ethereum.crypto.HashUtil; -import org.ethereum.db.Config; +import org.ethereum.manager.WorldManager; import org.ethereum.trie.Trie; import org.ethereum.util.ByteUtil; import org.ethereum.util.RLP; @@ -22,7 +22,7 @@ import java.util.List; */ public class Block { - /* A scalar value equal to the mininum limit of gas expenditure per block */ + /* A scalar longValue equal to the mininum limit of gas expenditure per block */ private static long MIN_GAS_LIMIT = BigInteger.valueOf(10).pow(4).longValue(); private BlockHeader header; @@ -40,7 +40,6 @@ public class Block { private boolean parsed = false; private byte[] hash; - private Trie accountState; private Trie txsState; /* Constructors */ @@ -57,9 +56,8 @@ public class Block { this.header = new BlockHeader(parentHash, unclesHash, coinbase, difficulty, number, minGasPrice, gasLimit, gasUsed, timestamp, extraData, nonce); - this.accountState = new Trie(Config.STATE_DB.getDb()); this.txsState = new Trie(null); - this.header.setStateRoot(accountState.getRootHash()); + this.header.setStateRoot(WorldManager.instance.allAccountsState.getRootHash()); this.header.setTxTrieRoot(txsState.getRootHash()); this.transactionsList = transactionsList; this.uncleList = uncleList; @@ -167,10 +165,6 @@ public class Block { return this.header.getNonce(); } - public Trie getAccountState() { - return this.accountState; - } - public Trie getTxsState() { return this.txsState; } @@ -277,12 +271,13 @@ public class Block { * - update state object */ -// this.accountState.update(); +// this.allAccountsState.update(); } public byte[] updateState(byte[] key, byte[] value) { - this.accountState.update(key, value); - byte[] stateRoot = this.accountState.getRootHash(); + + WorldManager.instance.allAccountsState.update(key, value); + byte[] stateRoot = WorldManager.instance.allAccountsState.getRootHash(); this.header.setStateRoot(stateRoot); return stateRoot; } diff --git a/ethereumj-core/src/main/java/org/ethereum/core/Blockchain.java b/ethereumj-core/src/main/java/org/ethereum/core/Blockchain.java index 2c08d939..06164e0b 100644 --- a/ethereumj-core/src/main/java/org/ethereum/core/Blockchain.java +++ b/ethereumj-core/src/main/java/org/ethereum/core/Blockchain.java @@ -1,22 +1,19 @@ package org.ethereum.core; -import java.io.IOException; -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.manager.WorldManager; import org.ethereum.net.message.StaticMessages; -import org.ethereum.net.submit.PendingTransaction; +import org.ethereum.net.submit.WalletTransaction; import org.iq80.leveldb.DBIterator; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.spongycastle.util.encoders.Hex; +import java.io.IOException; +import java.util.*; + +import static org.ethereum.core.Denomination.*; + public class Blockchain extends ArrayList { private static final long serialVersionUID = -143590724563460486L; @@ -28,11 +25,16 @@ public class Blockchain extends ArrayList { private long gasPrice = 1000; private Block lastBlock; - private Map pendingTransactions = - Collections.synchronizedMap(new HashMap()); + + // This map of transaction designed + // to approve the tx by external trusted peer + private Map walletTransactions = + Collections.synchronizedMap(new HashMap()); + + public Blockchain(Wallet wallet) { - this.db = Config.CHAIN_DB; + this.db = WorldManager.instance.chainDB; this.wallet = wallet; this.loadChain(); } @@ -43,8 +45,6 @@ public class Blockchain extends ArrayList { public void addBlocks(List blocks) { - // TODO: redesign this part when the state part and the genesis block is ready - if (blocks.isEmpty()) return; @@ -71,12 +71,12 @@ public class Blockchain extends ArrayList { if (logger.isDebugEnabled()) logger.debug("block added to the chain with hash: {}", Hex.toHexString(block.getHash())); } - // Remove all pending transactions as they already approved by the net + // Remove all wallet 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); + removeWalletTransaction(tx); } } logger.info("*** Block chain size: [ {} ]", this.size()); @@ -84,7 +84,12 @@ public class Blockchain extends ArrayList { private void addBlock(Block block) { this.wallet.processBlock(block); - this.gasPrice = block.getMinGasPrice(); + + // that is the genesis case , we don't want to rely + // on this price will use default 10000000000000 + // todo: refactor this longValue some constant defaults class 10000000000000L + this.gasPrice = (block.getMinGasPrice() == 0) ? 10 * SZABO.longValue() : block.getMinGasPrice(); + if(lastBlock == null || block.getNumber() > lastBlock.getNumber()) this.lastBlock = block; this.add(block); @@ -93,7 +98,12 @@ public class Blockchain extends ArrayList { public long getGasPrice() { return gasPrice; } - + + + + + + /*********************************************************************** * 1) the dialog put a pending transaction on the list * 2) the dialog send the transaction to a net @@ -101,24 +111,24 @@ public class Blockchain extends ArrayList { * 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) { + public WalletTransaction addWalletTransaction(Transaction transaction) { String hash = Hex.toHexString(transaction.getHash()); logger.info("pending transaction placed hash: {} ", hash ); - PendingTransaction pendingTransaction = pendingTransactions.get(hash); - if (pendingTransaction != null) - pendingTransaction.incApproved(); + WalletTransaction walletTransaction = this.walletTransactions.get(hash); + if (walletTransaction != null) + walletTransaction.incApproved(); else { - pendingTransaction = new PendingTransaction(transaction); - pendingTransactions.put(hash, pendingTransaction); + walletTransaction = new WalletTransaction(transaction); + this.walletTransactions.put(hash, walletTransaction); } - return pendingTransaction; + return walletTransaction; } - public void removePendingTransaction(Transaction transaction){ + public void removeWalletTransaction(Transaction transaction){ String hash = Hex.toHexString(transaction.getHash()); logger.info("pending transaction removed with hash: {} ", hash ); - pendingTransactions.remove(hash); + walletTransactions.remove(hash); } public byte[] getLatestBlockHash(){ diff --git a/ethereumj-core/src/main/java/org/ethereum/core/Denomination.java b/ethereumj-core/src/main/java/org/ethereum/core/Denomination.java index 8e2b6b97..edfbc6f7 100644 --- a/ethereumj-core/src/main/java/org/ethereum/core/Denomination.java +++ b/ethereumj-core/src/main/java/org/ethereum/core/Denomination.java @@ -17,11 +17,12 @@ public enum Denomination { private Denomination(BigInteger value) { this.amount = value; } - + public BigInteger getDenomination() { return amount; } - + public long longValue() {return getDenomination().longValue();} + private static BigInteger newBigInt(int value) { return BigInteger.valueOf(10).pow(value); } diff --git a/ethereumj-core/src/main/java/org/ethereum/core/Genesis.java b/ethereumj-core/src/main/java/org/ethereum/core/Genesis.java index 5058384e..2dc391c5 100644 --- a/ethereumj-core/src/main/java/org/ethereum/core/Genesis.java +++ b/ethereumj-core/src/main/java/org/ethereum/core/Genesis.java @@ -1,14 +1,14 @@ package org.ethereum.core; -import java.math.BigInteger; - import org.ethereum.crypto.HashUtil; -import org.ethereum.db.Config; +import org.ethereum.manager.WorldManager; import org.ethereum.util.RLP; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.spongycastle.util.encoders.Hex; +import java.math.BigInteger; + public class Genesis extends Block { Logger logger = LoggerFactory.getLogger(this.getClass()); @@ -54,7 +54,7 @@ public class Genesis extends Block { logger.info("Genesis-hash: " + Hex.toHexString(this.getHash())); logger.info("Genesis-stateRoot: " + Hex.toHexString(this.getStateRoot())); - Config.CHAIN_DB.put(getParentHash(), getEncoded()); + WorldManager.instance.chainDB.put(getParentHash(), getEncoded()); } public static Block getInstance() { diff --git a/ethereumj-core/src/main/java/org/ethereum/core/Transaction.java b/ethereumj-core/src/main/java/org/ethereum/core/Transaction.java index 4f550cd1..1a1de3cd 100644 --- a/ethereumj-core/src/main/java/org/ethereum/core/Transaction.java +++ b/ethereumj-core/src/main/java/org/ethereum/core/Transaction.java @@ -12,6 +12,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.spongycastle.util.BigIntegers; +import java.math.BigInteger; import java.security.SignatureException; import java.util.Arrays; @@ -76,7 +77,7 @@ public class Transaction { /* creation contract tx * [ nonce, gasPrice, gasLimit, 0000000000000000, endowment, init, signature(v, r, s) ] * or simple send tx - * [ nonce, gasPrice, gasLimit, receiveAddress, value, data, signature(v, r, s) ] + * [ nonce, gasPrice, gasLimit, receiveAddress, longValue, data, signature(v, r, s) ] */ public Transaction(byte[] nonce, byte[] gasPrice, byte[] gasLimit, byte[] receiveAddress, byte[] value, byte[] data) { this.nonce = nonce; @@ -129,6 +130,8 @@ public class Transaction { public byte[] getNonce() { if (!parsed) rlpParse(); + + if (nonce == null) return new byte[]{0}; return nonce; } diff --git a/ethereumj-core/src/main/java/org/ethereum/db/Config.java b/ethereumj-core/src/main/java/org/ethereum/db/Config.java deleted file mode 100644 index 9266214e..00000000 --- a/ethereumj-core/src/main/java/org/ethereum/db/Config.java +++ /dev/null @@ -1,8 +0,0 @@ -package org.ethereum.db; - -public class Config { - - public static Database CHAIN_DB = new Database("blockchain"); - public static Database STATE_DB = new Database("state"); - -} \ No newline at end of file diff --git a/ethereumj-core/src/main/java/org/ethereum/db/Database.java b/ethereumj-core/src/main/java/org/ethereum/db/Database.java index 78e61c28..97952c27 100644 --- a/ethereumj-core/src/main/java/org/ethereum/db/Database.java +++ b/ethereumj-core/src/main/java/org/ethereum/db/Database.java @@ -15,7 +15,7 @@ import org.slf4j.LoggerFactory; /** * Generic interface for Ethereum database * - * LevelDB key/value pair DB implementation will be used. + * LevelDB key/longValue 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 @@ -60,12 +60,12 @@ public class Database { } } - /** Insert object(value) (key = sha3(value)) */ + /** Insert object(longValue) (key = sha3(longValue)) */ public void put(byte[] key, byte[] value) { db.put(key, value); } - /** Get object (key) -> value */ + /** Get object (key) -> longValue */ public byte[] get(byte[] key) { return db.get(key); } diff --git a/ethereumj-core/src/main/java/org/ethereum/gui/ToolBar.java b/ethereumj-core/src/main/java/org/ethereum/gui/ToolBar.java index e8050884..c73c7cf0 100644 --- a/ethereumj-core/src/main/java/org/ethereum/gui/ToolBar.java +++ b/ethereumj-core/src/main/java/org/ethereum/gui/ToolBar.java @@ -1,13 +1,12 @@ package org.ethereum.gui; -import org.ethereum.db.Config; import org.ethereum.manager.MainData; +import org.ethereum.manager.WorldManager; import org.ethereum.util.Utils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.swing.*; - import java.awt.*; import java.awt.event.ItemEvent; import java.awt.event.ItemListener; @@ -74,8 +73,8 @@ public class ToolBar extends JFrame { addWindowListener(new WindowAdapter() { @Override public void windowClosing(WindowEvent e) { - Config.CHAIN_DB.close(); - Config.STATE_DB.close(); + + WorldManager.instance.close(); } }); @@ -124,7 +123,7 @@ public class ToolBar extends JFrame { logToggle = new JToggleButton(); logToggle.setIcon(image_2); - logToggle.setToolTipText("Log Console"); + logToggle.setToolTipText("Connect"); logToggle.setContentAreaFilled(true); logToggle.setBackground(Color.WHITE); logToggle.setBorderPainted(false); diff --git a/ethereumj-core/src/main/java/org/ethereum/manager/MainData.java b/ethereumj-core/src/main/java/org/ethereum/manager/MainData.java index 95f1d085..c2fee63a 100644 --- a/ethereumj-core/src/main/java/org/ethereum/manager/MainData.java +++ b/ethereumj-core/src/main/java/org/ethereum/manager/MainData.java @@ -48,12 +48,17 @@ public class MainData { wallet.importKey(cowAddr); AccountState state = wallet.getAddressState(key.getAddress()); - state.addToBalance(BigInteger.valueOf(2).pow(200)); // 1606938044258990275541962092341162602522202993782792835301376 + state.addToBalance(BigInteger.valueOf(2).pow(200)); wallet.importKey(HashUtil.sha3("cat".getBytes())); + String secret = CONFIG.coinbaseSecret(); + byte[] cbAddr = HashUtil.sha3(secret.getBytes()); + wallet.importKey(cbAddr); + + // Initialize Blockchain blockChain = new Blockchain(wallet); - + // Initialize PeerData try { InetAddress ip = InetAddress.getByName(CONFIG.peerDiscoveryIP()); @@ -64,9 +69,9 @@ public class MainData { } catch (UnknownHostException e) { e.printStackTrace(); System.exit(-1); - } + } } - + public Blockchain getBlockchain() { return blockChain; } diff --git a/ethereumj-core/src/main/java/org/ethereum/manager/WorldManager.java b/ethereumj-core/src/main/java/org/ethereum/manager/WorldManager.java new file mode 100644 index 00000000..7e0aa372 --- /dev/null +++ b/ethereumj-core/src/main/java/org/ethereum/manager/WorldManager.java @@ -0,0 +1,122 @@ +package org.ethereum.manager; + +import org.ethereum.core.AccountState; +import org.ethereum.core.Transaction; +import org.ethereum.db.Database; +import org.ethereum.trie.Trie; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.spongycastle.util.Arrays; +import org.spongycastle.util.encoders.Hex; + +import java.math.BigInteger; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * www.ethereumJ.com + * User: Roman Mandeleil + * Created on: 07/06/2014 10:08 + */ + +public class WorldManager { + + Logger logger = LoggerFactory.getLogger("main"); + + public static WorldManager instance = new WorldManager(); + + private Map pendingTransactions = + Collections.synchronizedMap(new HashMap()); + + public Database chainDB = new Database("blockchain"); + public Database stateDB = new Database("state"); + + public Trie allAccountsState = new Trie(stateDB.getDb()); + + + public void applyTransaction(Transaction tx){ + + // todo: refactor the wallet transactions to the world manager + MainData.instance.getBlockchain().addWalletTransaction(tx); + + // 1. VALIDATE THE NONCE + byte[] senderAddress = tx.getSender(); + byte[] stateData = allAccountsState.get(senderAddress); + + if (stateData == null) { + if (logger.isWarnEnabled()) + logger.warn("No such address: {}", Hex.toHexString(senderAddress)); + return; + } + + AccountState senderState = new AccountState(stateData); + if (senderState.getNonce().compareTo(new BigInteger(tx.getNonce())) != 0){ + + if (logger.isWarnEnabled()) + logger.warn("Invalid nonce account.nonce={} tx.nonce={}", + senderState.getNonce(), + new BigInteger(tx.getNonce())); + return; + } + + + // 2. FIND OUT WHAT IS THE TRANSACTION TYPE + if (tx.isContractCreation()){ + + // todo 0. run the init method + + + } else{ + + AccountState recieverState; + byte[] accountData = this.allAccountsState.get(tx.getReceiveAddress()); + if (accountData.length == 0){ + + if (logger.isInfoEnabled()) + logger.info("New account created address={}", + Hex.toHexString(tx.getReceiveAddress())); + recieverState = new AccountState(tx.getKey()); + } else { + recieverState = new AccountState(accountData); + } + + // APPLY THE BALANCE VALUE + recieverState.addToBalance(new BigInteger(1, tx.getValue())); + senderState.addToBalance(new BigInteger(1, tx.getValue()).negate()); + + + // todo 2. check if the address is a contract, if it is perform contract call + + + if (senderState.getBalance().compareTo(BigInteger.ZERO) == 1){ + + senderState.incrementNonce(); + allAccountsState.update(tx.getSender(), senderState.getEncoded()); + allAccountsState.update(tx.getReceiveAddress(), recieverState.getEncoded()); + } + + } + + pendingTransactions.put(Hex.toHexString(tx.getHash()), tx); + } + + public void applyTransactionList(List txList){ + for (Transaction tx : txList){ + applyTransaction(tx); + } + } + + public void applyBlock(){ + + } + + + + public void close(){ + chainDB.close(); + stateDB.close(); + } + +} diff --git a/ethereumj-core/src/main/java/org/ethereum/net/client/ClientPeer.java b/ethereumj-core/src/main/java/org/ethereum/net/client/ClientPeer.java index 1e42f63b..eb661f4c 100644 --- a/ethereumj-core/src/main/java/org/ethereum/net/client/ClientPeer.java +++ b/ethereumj-core/src/main/java/org/ethereum/net/client/ClientPeer.java @@ -7,6 +7,7 @@ import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket.nio.NioSocketChannel; import io.netty.handler.timeout.ReadTimeoutHandler; +import org.ethereum.config.SystemProperties; import org.ethereum.core.Transaction; import org.ethereum.gui.PeerListener; import org.ethereum.manager.MainData; @@ -18,6 +19,9 @@ import org.slf4j.LoggerFactory; import org.spongycastle.util.encoders.Hex; import java.util.ArrayList; +import java.util.concurrent.TimeUnit; + +import static org.ethereum.config.SystemProperties.CONFIG; /** @@ -63,7 +67,8 @@ public class ClientPeer { @Override public void initChannel(NioSocketChannel ch) throws Exception { - ch.pipeline().addLast("readTimeoutHandler", new ReadTimeoutHandler(15)); + ch.pipeline().addLast("readTimeoutHandler", + new ReadTimeoutHandler(CONFIG.activePeerChannelTimeout(), TimeUnit.SECONDS)); ch.pipeline().addLast(new EthereumFrameDecoder()); ch.pipeline().addLast(handler); } diff --git a/ethereumj-core/src/main/java/org/ethereum/net/client/EthereumProtocolHandler.java b/ethereumj-core/src/main/java/org/ethereum/net/client/EthereumProtocolHandler.java index 4d820ba9..b82f5939 100644 --- a/ethereumj-core/src/main/java/org/ethereum/net/client/EthereumProtocolHandler.java +++ b/ethereumj-core/src/main/java/org/ethereum/net/client/EthereumProtocolHandler.java @@ -7,14 +7,13 @@ import io.netty.channel.ChannelInboundHandlerAdapter; import io.netty.channel.ChannelOption; import io.netty.channel.FixedRecvByteBufAllocator; -import java.util.List; -import java.util.Timer; -import java.util.TimerTask; +import java.util.*; import org.ethereum.core.Block; import org.ethereum.core.Transaction; import org.ethereum.gui.PeerListener; import org.ethereum.manager.MainData; +import org.ethereum.manager.WorldManager; import org.ethereum.net.Command; import org.ethereum.net.message.BlocksMessage; import org.ethereum.net.message.DisconnectMessage; @@ -201,13 +200,13 @@ public class EthereumProtocolHandler extends ChannelInboundHandlerAdapter { RLPList rlpList = RLP.decode2(payload); TransactionsMessage transactionsMessage = new TransactionsMessage(rlpList); - for (Transaction tx : transactionsMessage.getTransactions()) - MainData.instance.getBlockchain().addPendingTransaction(tx); - // todo: if you got transactions send it to your connected peers + WorldManager.instance.applyTransactionList(transactionsMessage.getTransactions()); + logger.info(transactionsMessage.toString()); if (peerListener != null) peerListener.console(transactionsMessage.toString()); } + // got BLOCKS if (Command.fromInt(command) == BLOCKS) { logger.info("[Recv: BLOCKS]"); @@ -260,6 +259,7 @@ public class EthereumProtocolHandler extends ChannelInboundHandlerAdapter { logger.info(blocksMessage.toString()); if (peerListener != null) peerListener.console(blocksMessage.toString()); } + // got GETCHAIN if (Command.fromInt(command) == GET_CHAIN) { logger.info("[Recv: GET_CHAIN]"); @@ -271,6 +271,7 @@ public class EthereumProtocolHandler extends ChannelInboundHandlerAdapter { logger.info(getChainMessage.toString()); if (peerListener != null) peerListener.console(getChainMessage.toString()); } + // got NOTINCHAIN if (Command.fromInt(command) == NOT_IN_CHAIN) { logger.info("[Recv: NOT_IN_CHAIN]"); @@ -282,11 +283,20 @@ public class EthereumProtocolHandler extends ChannelInboundHandlerAdapter { logger.info(notInChainMessage.toString()); if (peerListener != null) peerListener.console(notInChainMessage.toString()); } + // got GETTRANSACTIONS if (Command.fromInt(command) == GET_TRANSACTIONS) { logger.info("[Recv: GET_TRANSACTIONS]"); if (peerListener != null) peerListener.console("[Recv: GET_TRANSACTIONS]"); - // todo: send the queue of the transactions + + // todo: return it in the future +// Collection pendingTxList = +// MainData.instance.getBlockchain().getPendingTransactionList(); + +// TransactionsMessage txMsg = +// new TransactionsMessage(new ArrayList(pendingTxList)); + +// sendMsg(txMsg, ctx); } } diff --git a/ethereumj-core/src/main/java/org/ethereum/net/submit/TransactionTask.java b/ethereumj-core/src/main/java/org/ethereum/net/submit/TransactionTask.java index 7247d343..71a62318 100644 --- a/ethereumj-core/src/main/java/org/ethereum/net/submit/TransactionTask.java +++ b/ethereumj-core/src/main/java/org/ethereum/net/submit/TransactionTask.java @@ -34,18 +34,18 @@ public class TransactionTask implements Callable { ClientPeer peer = MainData.instance.getActivePeer(); - PendingTransaction pendingTransaction = MainData.instance - .getBlockchain().addPendingTransaction(tx); + WalletTransaction walletTransaction = MainData.instance + .getBlockchain().addWalletTransaction(tx); peer.sendTransaction(tx); - while(pendingTransaction.getApproved() < 1 ){ + while(walletTransaction.getApproved() < 1 ){ sleep(10); } - logger.info("return approved: {}", pendingTransaction.getApproved()); + logger.info("return approved: {}", walletTransaction.getApproved()); } catch (Throwable th) { logger.info("exception caugh: {}", th.getCause()); - MainData.instance.getBlockchain().removePendingTransaction(tx); + MainData.instance.getBlockchain().removeWalletTransaction(tx); } return null; diff --git a/ethereumj-core/src/main/java/org/ethereum/net/submit/PendingTransaction.java b/ethereumj-core/src/main/java/org/ethereum/net/submit/WalletTransaction.java similarity index 83% rename from ethereumj-core/src/main/java/org/ethereum/net/submit/PendingTransaction.java rename to ethereumj-core/src/main/java/org/ethereum/net/submit/WalletTransaction.java index 775d56c9..e647dd7e 100644 --- a/ethereumj-core/src/main/java/org/ethereum/net/submit/PendingTransaction.java +++ b/ethereumj-core/src/main/java/org/ethereum/net/submit/WalletTransaction.java @@ -8,12 +8,12 @@ import org.ethereum.core.Transaction; * Created on: 23/05/2014 18:41 */ -public class PendingTransaction { +public class WalletTransaction { private Transaction tx; int approved = 0; // each time the tx got from the wire this value increased - public PendingTransaction(Transaction tx) { + public WalletTransaction(Transaction tx) { this.tx = tx; } diff --git a/ethereumj-core/src/main/java/org/ethereum/util/CompactEncoder.java b/ethereumj-core/src/main/java/org/ethereum/util/CompactEncoder.java index 6a6dee82..2ab4332d 100644 --- a/ethereumj-core/src/main/java/org/ethereum/util/CompactEncoder.java +++ b/ethereumj-core/src/main/java/org/ethereum/util/CompactEncoder.java @@ -23,13 +23,13 @@ import static org.spongycastle.util.encoders.Hex.toHexString; * * An alternative way of thinking about this to not think of there being a terminator symbol, * but instead treat bit specifying the existence of the terminator symbol as a bit specifying - * that the given node encodes a final node, where the value is an actual value, rather than + * that the given node encodes a final node, where the value is an actual value, rather than * the hash of yet another node. * * To solve both of these issues, we force the first nibble of the final byte-stream to encode * two flags, specifying oddness of length (ignoring the 'T' symbol) and terminator status; * these are placed, respectively, into the two lowest significant bits of the first nibble. - * In the case of an even-length hex string, we must introduce a second nibble (of value zero) + * In the case of an even-length hex string, we must introduce a second nibble (of value zero) * to ensure the hex-string is even in length and thus is representable by a whole number of bytes. * * Examples: @@ -80,7 +80,7 @@ public class CompactEncoder { /** * Unpack a binary string to its nibbles equivalent * - * @param string of binary data + * @param str of binary data * @return array of nibbles in byte-format */ public static byte[] unpackToNibbles(byte[] str) { diff --git a/ethereumj-core/src/main/java/org/ethereum/util/RLP.java b/ethereumj-core/src/main/java/org/ethereum/util/RLP.java index f1af2ce9..6726c5a9 100644 --- a/ethereumj-core/src/main/java/org/ethereum/util/RLP.java +++ b/ethereumj-core/src/main/java/org/ethereum/util/RLP.java @@ -808,7 +808,8 @@ public class RLP { public static byte[] encodeElement(byte[] srcData) { - if (srcData == null) { + if ( srcData == null || + (srcData.length == 1 && srcData[0] == 0) ) { return new byte[]{(byte) 0x80}; } if (srcData.length == 1 && srcData[0] < 0x80) { diff --git a/ethereumj-core/src/main/java/org/ethereum/vm/Program.java b/ethereumj-core/src/main/java/org/ethereum/vm/Program.java index 39eee8f3..6ef5057e 100644 --- a/ethereumj-core/src/main/java/org/ethereum/vm/Program.java +++ b/ethereumj-core/src/main/java/org/ethereum/vm/Program.java @@ -17,43 +17,46 @@ import java.util.*; public class Program { - Logger logger = LoggerFactory.getLogger("VM"); - ProgramListener listener; + Logger logger = LoggerFactory.getLogger("VM"); + ProgramListener listener; - Stack stack = new Stack(); - Map storage = new HashMap(); - ByteBuffer memory = null; + Stack stack = new Stack(); + Map storage = new HashMap(); + ByteBuffer memory = null; - ByteBuffer hReturn = null; + ByteBuffer hReturn = null; - byte[] ops; - int pc = 0; - boolean stopped = false; - int spendGas = 0; + byte[] ops; + int pc = 0; + boolean stopped = false; - ProgramInvoke invokeData; + ProgramInvoke invokeData; - public Program(byte[] ops, ProgramInvoke invokeData) { + Map addressChange; + int spendGas = 0; - if (ops == null) - throw new RuntimeException("program can not run with ops: null"); - this.invokeData = invokeData; - this.ops = ops; - } + public Program(byte[] ops, ProgramInvoke invokeData) { - public byte getCurrentOp() { - return ops[pc]; - } + if (ops == null) throw new RuntimeException("program can not run with ops: null"); - public void stackPush(byte[] data) { - DataWord stackWord = new DataWord(data); - stack.push(stackWord); - } + this.invokeData = invokeData; + this.ops = ops; + } - public void stackPush(DataWord stackWord) { - stack.push(stackWord); - } + public byte getCurrentOp(){ + return ops[pc]; + } + + + public void stackPush(byte[] data){ + DataWord stackWord = new DataWord(data); + stack.push(stackWord); + } + + public void stackPush(DataWord stackWord){ + stack.push(stackWord); + } public int getPC() { return pc; @@ -72,296 +75,285 @@ public class Program { this.pc = pc; } - public boolean isStopped() { - return stopped; - } + public boolean isStopped(){ + return stopped; + } - public void stop() { - stopped = true; - } + public void stop(){ + stopped = true; + } - public void setHReturn(ByteBuffer buff) { - hReturn = buff; - } + public void setHReturn(ByteBuffer buff){ + hReturn = buff; + } - public void step() { - ++pc; - if (pc >= ops.length) - stop(); - } + public void step(){ + ++pc; + if (pc >= ops.length) stop(); + } - public byte[] sweep(int n) { + public byte[] sweep(int n){ - if (pc + n > ops.length) { - stop(); - throw new RuntimeException("pc overflow sweep n: " + n + " pc: " - + pc); - } + if (pc + n > ops.length) { + stop(); + throw new RuntimeException("pc overflow sweep n: " + n + " pc: " + pc); + } - byte[] data = Arrays.copyOfRange(ops, pc, pc + n); - pc += n; - if (pc >= ops.length) - stop(); + byte[] data = Arrays.copyOfRange(ops, pc, pc + n); + pc += n; + if (pc >= ops.length) stop(); - return data; - } + return data; + } - public DataWord stackPop() { + public DataWord stackPop(){ - if (stack.size() == 0) { - stop(); - throw new RuntimeException("attempted pull action for empty stack"); - } - return stack.pop(); - }; + if (stack.size() == 0){ + stop(); + throw new RuntimeException("attempted pull action for empty stack"); + } + return stack.pop(); + }; - public int getMemSize() { + public int getMemSize(){ - int memSize = 0; - if (memory != null) - memSize = memory.limit(); - return memSize; - } + int memSize = 0; + if (memory != null) memSize = memory.limit(); + return memSize; + } - public void memorySave(DataWord addrB, DataWord value) { - memorySave(addrB.data, value.data); - } + public void memorySave(DataWord addrB, DataWord value){ + memorySave(addrB.data, value.data); + } - public void memorySave(byte[] addr, byte[] value) { + public void memorySave(byte[] addr, byte[] value){ - int address = new BigInteger(1, addr).intValue(); - allocateMemory(address, value); + int address = new BigInteger(1, addr).intValue(); + allocateMemory(address, value); - System.arraycopy(value, 0, memory.array(), address, value.length); - } + System.arraycopy(value, 0, memory.array(), address, value.length); + } - public DataWord memoryLoad(DataWord addr) { + public DataWord memoryLoad(DataWord addr){ - int address = new BigInteger(1, addr.getData()).intValue(); - allocateMemory(address, DataWord.ZERO.data); + int address = new BigInteger(1, addr.getData()).intValue(); + allocateMemory(address, DataWord.ZERO.data); - byte[] data = new byte[32]; - System.arraycopy(memory.array(), address, data, 0, 32); + byte[] data = new byte[32]; + System.arraycopy(memory.array(), address, data , 0 ,32); - return new DataWord(data); - } + return new DataWord(data); + } - public ByteBuffer memoryChunk(DataWord offsetData, DataWord sizeData) { + public ByteBuffer memoryChunk(DataWord offsetData, DataWord sizeData){ - int offset = offsetData.value().intValue(); - int size = sizeData.value().intValue(); + int offset = offsetData.value().intValue(); + int size = sizeData.value().intValue(); - byte[] chunk = new byte[size]; + byte[] chunk = new byte[size]; - if (memory.limit() < offset + size) - size = memory.limit() - offset; - - System.arraycopy(memory.array(), offset, chunk, 0, size); + if (memory.limit() < offset + size) size = memory.limit() - offset; - return ByteBuffer.wrap(chunk); - } - - private void allocateMemory(int address, byte[] value) { + System.arraycopy(memory.array(), offset, chunk, 0, size); - int memSize = 0; - if (memory != null) - memSize = memory.limit(); + return ByteBuffer.wrap(chunk); + } - // check if you need to allocate - if (memSize < (address + value.length)) { - int sizeToAllocate = 0; - if (memSize > address) { + private void allocateMemory(int address, byte[] value){ - sizeToAllocate = memSize + value.length; - } else { - sizeToAllocate = memSize + (address - memSize) + value.length; - } + int memSize = 0; + if (memory != null) memSize = memory.limit(); - // complete to 32 - sizeToAllocate = (sizeToAllocate % 32) == 0 ? sizeToAllocate - : sizeToAllocate + (32 - sizeToAllocate % 32); + // check if you need to allocate + if (memSize < (address + value.length)){ - sizeToAllocate = (sizeToAllocate == 0) ? 32 : sizeToAllocate; + int sizeToAllocate = 0; + if (memSize > address){ - ByteBuffer tmpMem = ByteBuffer.allocate(sizeToAllocate); - if (memory != null) - System.arraycopy(memory.array(), 0, tmpMem.array(), 0, - memory.limit()); + sizeToAllocate = memSize + value.length; + } else { + sizeToAllocate = memSize + (address - memSize) + value.length; + } - memory = tmpMem; - } - } + // complete to 32 + sizeToAllocate = (sizeToAllocate % 32)==0 ? sizeToAllocate : + sizeToAllocate + (32 - sizeToAllocate % 32); - public void spendGas(int gasValue) { - // todo: check it against avail gas - // todo: out of gas will revert the changes [YP 5, 6 ] - spendGas += gasValue; - } + sizeToAllocate = (sizeToAllocate == 0)? 32: sizeToAllocate; - public void storageSave(DataWord word1, DataWord word2) { - storageSave(word1.getData(), word2.getData()); - } + ByteBuffer tmpMem = ByteBuffer.allocate(sizeToAllocate); + if (memory != null) + System.arraycopy(memory.array(), 0, tmpMem.array(), 0, memory.limit()); - public void storageSave(byte[] key, byte[] val) { - DataWord keyWord = new DataWord(key); - DataWord valWord = new DataWord(val); - storage.put(keyWord, valWord); - } - - public DataWord getOwnerAddress() { - if (invokeData == null) - return new DataWord(new byte[0]); - return invokeData.getOwnerAddress(); - } + memory = tmpMem; + } + } - public DataWord getBalance() { - if (invokeData == null) - return new DataWord(new byte[0]); - return invokeData.getBalance(); - } + public void sendToAddress(byte[] addr, DataWord bChange ){ - public DataWord getOriginAddress() { - if (invokeData == null) - return new DataWord(new byte[0]); - return invokeData.getOriginAddress(); - } + DataWord currentBChange = addressChange.get(addr); + if (currentBChange == null){ + addressChange.put(addr, bChange); + } else { + currentBChange.add(bChange); + } + } - public DataWord getCallerAddress() { - if (invokeData == null) - return new DataWord(new byte[0]); - return invokeData.getCallerAddress(); - } - - public DataWord getMinGasPrice() { - if (invokeData == null) - return new DataWord(new byte[0]); - return invokeData.getMinGasPrice(); - } - - public DataWord getCallValue() { - if (invokeData == null) - return new DataWord(new byte[0]); - return invokeData.getCallValue(); - } - - public DataWord getDataSize() { - if (invokeData == null) - return new DataWord(new byte[0]); - return invokeData.getDataSize(); - } - - public DataWord getDataValue(DataWord index) { - if (invokeData == null) - return new DataWord(new byte[0]); - return invokeData.getDataValue(index); - } - - public byte[] getDataCopy(DataWord offset, DataWord length) { - if (invokeData == null) - return new byte[0]; - return invokeData.getDataCopy(offset, length); - } - - public DataWord storageLoad(DataWord key) { - return storage.get(key); - } - - public void fullTrace() { - - // todo: add gas to full trace calc - - if (logger.isDebugEnabled()) { - - StringBuilder stackData = new StringBuilder(); - for (int i = 0; i < stack.size(); ++i) { - - stackData.append(" ").append(stack.get(i)); - if (i < stack.size() - 1) - stackData.append("\n"); - } - if (stackData.length() > 0) - stackData.insert(0, "\n"); - - StringBuilder storageData = new StringBuilder(); - for (DataWord key : storage.keySet()) { - - storageData.append(" ").append(key).append(" -> ") - .append(storage.get(key)).append("\n"); - } - if (storageData.length() > 0) - storageData.insert(0, "\n"); - - StringBuilder memoryData = new StringBuilder(); - StringBuilder oneLine = new StringBuilder(); - for (int i = 0; memory != null && i < memory.limit(); ++i) { - - byte value = memory.get(i); - oneLine.append(Utils.oneByteToHexString(value)).append(" "); - - if ((i + 1) % 16 == 0) { - - String tmp = String.format("[%4s]-[%4s]", - Integer.toString(i - 15, 16), - Integer.toString(i, 16)).replace(" ", "0"); - memoryData.append("").append(tmp).append(" "); - memoryData.append(oneLine); - if (i < memory.limit()) - memoryData.append("\n"); - oneLine.setLength(0); - } - } - if (memoryData.length() > 0) - memoryData.insert(0, "\n"); - - StringBuilder opsString = new StringBuilder(); - for (int i = 0; i < ops.length; ++i) { - - String tmpString = Integer.toString(ops[i] & 0xFF, 16); - tmpString = tmpString.length() == 1 ? "0" + tmpString - : tmpString; - - if (i != pc) - opsString.append(tmpString); - else - opsString.append(" >>").append(tmpString).append(""); - - } - if (pc >= ops.length) - opsString.append(" >>"); - if (opsString.length() > 0) - opsString.insert(0, "\n "); - - logger.debug(" -- OPS -- {}", opsString); - logger.debug(" -- STACK -- {}", stackData); - logger.debug(" -- MEMORY -- {}", memoryData); - logger.debug(" -- STORAGE -- {}\n", storageData); - - StringBuilder global = new StringBuilder("\n"); - if (stackData.length() > 0) - stackData.append("\n"); - - global.append(" -- OPS -- ").append(opsString).append("\n"); - global.append(" -- STACK -- ").append(stackData).append("\n"); - global.append(" -- MEMORY -- ").append(memoryData).append("\n"); - global.append(" -- STORAGE -- ").append(storageData).append("\n"); - - if (hReturn != null) { - global.append("\n HReturn: ").append( - Hex.toHexString(hReturn.array())); - } - - if (listener != null) { - listener.output(global.toString()); - } - } - } - - public void addListener(ProgramListener listener) { - this.listener = listener; - } - - public interface ProgramListener { - public void output(String out); - } + + public void spendGas(int gasValue){ + // todo: check it against avail gas + // todo: out of gas will revert the changes [YP 5, 6 ] + spendGas += gasValue; + } + + public void storageSave(DataWord word1, DataWord word2){ + storageSave(word1.getData(), word2.getData()); + } + + public void storageSave(byte[] key, byte[] val){ + DataWord keyWord = new DataWord(key); + DataWord valWord = new DataWord(val); + storage.put(keyWord, valWord); + } + + public DataWord getOwnerAddress(){ + if (invokeData == null) return new DataWord( new byte[0]); + return invokeData.getOwnerAddress(); + } + + public DataWord getBalance(){ + if (invokeData == null) return new DataWord( new byte[0]); + return invokeData.getBalance(); + } + + public DataWord getOriginAddress(){ + if (invokeData == null) return new DataWord( new byte[0]); + return invokeData.getOriginAddress(); + } + + public DataWord getCallerAddress(){ + if (invokeData == null) return new DataWord( new byte[0]); + return invokeData.getCallerAddress(); + } + + public DataWord getMinGasPrice(){ + if (invokeData == null) return new DataWord( new byte[0]); + return invokeData.getMinGasPrice(); + } + + public DataWord getCallValue(){ + if (invokeData == null) return new DataWord( new byte[0]); + return invokeData.getCallValue(); + } + + public DataWord getDataSize(){ + if (invokeData == null) return new DataWord( new byte[0]); + return invokeData.getDataSize(); + } + + public DataWord getDataValue(DataWord index){ + if (invokeData == null) return new DataWord( new byte[0]); + return invokeData.getDataValue(index); + } + + public byte[] getDataCopy(DataWord offset, DataWord length){ + if (invokeData == null) return new byte[0]; + return invokeData.getDataCopy(offset, length); + } + + public DataWord storageLoad(DataWord key){ + return storage.get(key); + } + + + public void fullTrace(){ + + // todo: add gas to full trace calc + + if (logger.isDebugEnabled()){ + + StringBuilder stackData = new StringBuilder(); + for (int i = 0; i < stack.size(); ++i){ + + stackData.append(" ").append(stack.get(i)); + if (i < stack.size() - 1) stackData.append("\n"); + } + if (stackData.length() > 0) stackData.insert(0, "\n"); + + StringBuilder storageData = new StringBuilder(); + for (DataWord key : storage.keySet()){ + + storageData.append(" ").append(key).append(" -> ").append(storage.get(key)).append("\n"); + } + if (storageData.length() > 0) storageData.insert(0, "\n"); + + StringBuilder memoryData = new StringBuilder(); + StringBuilder oneLine = new StringBuilder(); + for (int i = 0; memory != null && i < memory.limit(); ++i){ + + byte value = memory.get(i); + oneLine.append(Utils.oneByteToHexString(value)).append(" "); + + if ((i + 1) % 16 == 0) { + + String tmp = String.format("[%4s]-[%4s]", Integer.toString(i - 15, 16), + Integer.toString(i, 16)).replace(" ", "0"); + memoryData.append("" ).append(tmp).append(" "); + memoryData.append(oneLine); + if (i < memory.limit()) memoryData.append("\n"); + oneLine.setLength(0); + } + } + if (memoryData.length() > 0) memoryData.insert(0, "\n"); + + StringBuilder opsString = new StringBuilder(); + for (int i = 0; i < ops.length; ++i){ + + String tmpString = Integer.toString(ops[i] & 0xFF, 16); + tmpString = tmpString.length() == 1? "0" + tmpString : tmpString; + + if (i != pc) + opsString.append(tmpString); + else + opsString.append(" >>").append(tmpString).append(""); + + } + if (pc >= ops.length) opsString.append(" >>"); + if (opsString.length() > 0) opsString.insert(0, "\n "); + + logger.debug(" -- OPS -- {}", opsString); + logger.debug(" -- STACK -- {}", stackData); + logger.debug(" -- MEMORY -- {}", memoryData); + logger.debug(" -- STORAGE -- {}\n", storageData); + + + StringBuilder global = new StringBuilder("\n"); + if (stackData.length() > 0) stackData.append("\n"); + + global.append(" -- OPS -- ").append(opsString).append("\n"); + global.append(" -- STACK -- ").append(stackData).append("\n"); + global.append(" -- MEMORY -- ").append(memoryData).append("\n"); + global.append(" -- STORAGE -- ").append(storageData).append("\n"); + + if (hReturn != null){ + global.append("\n HReturn: ").append(Hex.toHexString(hReturn.array())); + } + + if (listener != null){ + listener.output(global.toString()); + } + + }; + } + + + + public void addListener(ProgramListener listener){ + this.listener = listener; + } + + public interface ProgramListener{ + public void output(String out); + } } diff --git a/ethereumj-core/src/main/java/org/ethereum/vm/VM.java b/ethereumj-core/src/main/java/org/ethereum/vm/VM.java index 0c575b7a..af5c2d5c 100644 --- a/ethereumj-core/src/main/java/org/ethereum/vm/VM.java +++ b/ethereumj-core/src/main/java/org/ethereum/vm/VM.java @@ -527,10 +527,29 @@ public class VM { program.stackPush(data); } break; - case CREATE: - break; - case CALL: - break; + case CREATE:{ + DataWord gas = program.stackPop(); + DataWord inOffset = program.stackPop(); + DataWord inSize = program.stackPop(); + + // todo: implement contract creation + + program.step(); + } + break; + case CALL:{ + DataWord gas = program.stackPop(); + DataWord toAddress = program.stackPop(); + DataWord value = program.stackPop(); + + program.sendToAddress(toAddress.data, value); + + // todo: find out if we should or not execute + // todo: the contract for real + + program.step(); + } + break; case RETURN:{ DataWord offset = program.stackPop(); diff --git a/ethereumj-core/src/main/resources/system.properties b/ethereumj-core/src/main/resources/system.properties index aaa27411..b4b81916 100644 --- a/ethereumj-core/src/main/resources/system.properties +++ b/ethereumj-core/src/main/resources/system.properties @@ -26,8 +26,9 @@ peer.discovery.port = 30303 # Nick #peer.active.ip = 82.217.72.169 #peer.active.port = 30303 - -# RomanJ + + +# RomanJ general peer.active.ip = 54.211.14.10 peer.active.port = 50505 @@ -58,7 +59,13 @@ peer.discovery.timeout = 2 # transaction got approved when # include into a transactions msg # retrieved from the peer [seconds] -transaction.approve.timeout = 5 +transaction.approve.timeout = 360 + +# the parameter specifies how much +# time the active peer will wait +# for a message to come before kill +# the channel +active.peer.channel.timeout = 360 # default directory where we keep # basic Serpent samples relative @@ -70,3 +77,9 @@ samples.dir = samples # destroyed and all the data will be # downloaded from peers again database.reset = true + + +# this string is computed +# to be eventually the address +# that get the miner reward +coinbase.secret = "monkey" \ No newline at end of file