mirror of
https://github.com/status-im/ethereumj-personal.git
synced 2025-02-26 02:35:14 +00:00
Major refactoring :
WorldManager introduced WalletTransaction for wallet waiting tx Pending Transaction for block creation
This commit is contained in:
parent
dcf19fba08
commit
9319272a5a
@ -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();
|
||||
|
@ -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();
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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<Block> {
|
||||
|
||||
private static final long serialVersionUID = -143590724563460486L;
|
||||
@ -28,11 +25,16 @@ public class Blockchain extends ArrayList<Block> {
|
||||
private long gasPrice = 1000;
|
||||
private Block lastBlock;
|
||||
|
||||
private Map<String, PendingTransaction> pendingTransactions =
|
||||
Collections.synchronizedMap(new HashMap<String, PendingTransaction>());
|
||||
|
||||
// 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(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<Block> {
|
||||
|
||||
public void addBlocks(List<Block> 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<Block> {
|
||||
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<Block> {
|
||||
|
||||
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<Block> {
|
||||
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<Block> {
|
||||
* 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(){
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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() {
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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");
|
||||
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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<String, Transaction> pendingTransactions =
|
||||
Collections.synchronizedMap(new HashMap<String, Transaction>());
|
||||
|
||||
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<Transaction> txList){
|
||||
for (Transaction tx : txList){
|
||||
applyTransaction(tx);
|
||||
}
|
||||
}
|
||||
|
||||
public void applyBlock(){
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
public void close(){
|
||||
chainDB.close();
|
||||
stateDB.close();
|
||||
}
|
||||
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
@ -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<Transaction> pendingTxList =
|
||||
// MainData.instance.getBlockchain().getPendingTransactionList();
|
||||
|
||||
// TransactionsMessage txMsg =
|
||||
// new TransactionsMessage(new ArrayList(pendingTxList));
|
||||
|
||||
// sendMsg(txMsg, ctx);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -34,18 +34,18 @@ public class TransactionTask implements Callable<Transaction> {
|
||||
|
||||
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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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) {
|
||||
|
@ -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) {
|
||||
|
||||
|
@ -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<DataWord> stack = new Stack<DataWord>();
|
||||
Map<DataWord, DataWord> storage = new HashMap<DataWord, DataWord>();
|
||||
ByteBuffer memory = null;
|
||||
Stack<DataWord> stack = new Stack<DataWord>();
|
||||
Map<DataWord, DataWord> storage = new HashMap<DataWord, DataWord>();
|
||||
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<byte[], DataWord> 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);
|
||||
}
|
||||
}
|
||||
|
@ -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();
|
||||
|
@ -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"
|
Loading…
x
Reference in New Issue
Block a user