fix ton of bugs for poc-7 compatibility
This commit is contained in:
parent
aad53ba2c5
commit
b1c82cb59e
|
@ -16,6 +16,12 @@
|
||||||
|
|
||||||
(*) if [artifact.snapshot] is set the deploy will add timestamp to the package
|
(*) if [artifact.snapshot] is set the deploy will add timestamp to the package
|
||||||
|
|
||||||
|
|
||||||
|
delete api with bash:
|
||||||
|
|
||||||
|
curl -X DELETE https://api.bintray.com/packages/ethereum/maven/org.ethereum/versions/0.7.14.20141224.1153 &
|
||||||
|
|
||||||
|
|
||||||
-->
|
-->
|
||||||
|
|
||||||
|
|
||||||
|
@ -26,7 +32,7 @@
|
||||||
|
|
||||||
<property name="artifact.groupId" value="org.ethereum"/>
|
<property name="artifact.groupId" value="org.ethereum"/>
|
||||||
<property name="artifact.id" value="ethereumj"/>
|
<property name="artifact.id" value="ethereumj"/>
|
||||||
<property name="artifact.version" value="0.7.9"/>
|
<property name="artifact.version" value="0.7.14"/>
|
||||||
<property name="artifact.path" value="" />
|
<property name="artifact.path" value="" />
|
||||||
<property name="artifact.snapshot" value="snapshot" />
|
<property name="artifact.snapshot" value="snapshot" />
|
||||||
|
|
||||||
|
@ -144,7 +150,7 @@
|
||||||
|
|
||||||
<echo message="${artifact.full.path}/${artifact.id}-${artifact.version}${artifact.suffix}"/>
|
<echo message="${artifact.full.path}/${artifact.id}-${artifact.version}${artifact.suffix}"/>
|
||||||
|
|
||||||
<http url="https://api.bintray.com/content/${bintray.subject}/${bintray.repo}/${bintray.package}/${bintray.version}/${encoded.bintray.file.path}${artifact.suffix};publish=1"
|
<http url="https://api.bintray.com/content/${bintray.subject}/${bintray.repo}/${bintray.package}/${bintray.version}/${encoded.bintray.file.path}${artifact.suffix};publish=1;override=1"
|
||||||
method="PUT"
|
method="PUT"
|
||||||
printrequest="false"
|
printrequest="false"
|
||||||
printrequestheaders="true"
|
printrequestheaders="true"
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
<groupId>org.ethereum</groupId>
|
<groupId>org.ethereum</groupId>
|
||||||
<artifactId>ethereumj</artifactId>
|
<artifactId>ethereumj</artifactId>
|
||||||
<packaging>jar</packaging>
|
<packaging>jar</packaging>
|
||||||
<version>0.7.9</version>
|
<version>0.7.14</version>
|
||||||
<name>EthereumJ</name>
|
<name>EthereumJ</name>
|
||||||
<url>http://www.ethereumj.org</url>
|
<url>http://www.ethereumj.org</url>
|
||||||
|
|
||||||
|
|
|
@ -145,6 +145,12 @@ public class BlockchainImpl implements Blockchain {
|
||||||
block.getNumber());
|
block.getNumber());
|
||||||
|
|
||||||
if (blockStore.getBlockByHash(block.getHash()) != null){
|
if (blockStore.getBlockByHash(block.getHash()) != null){
|
||||||
|
|
||||||
|
if (logger.isDebugEnabled())
|
||||||
|
logger.debug("Block already exist hash: {}, number: {}",
|
||||||
|
Hex.toHexString(block.getHash()).substring(0, 6),
|
||||||
|
block.getNumber());
|
||||||
|
|
||||||
// retry of well known block
|
// retry of well known block
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -318,7 +324,7 @@ public class BlockchainImpl implements Blockchain {
|
||||||
stateLogger.info("apply block: [{}] tx: [{}] ", block.getNumber(), i);
|
stateLogger.info("apply block: [{}] tx: [{}] ", block.getNumber(), i);
|
||||||
|
|
||||||
TransactionExecutor executor = new TransactionExecutor(tx, block.getCoinbase(), track,
|
TransactionExecutor executor = new TransactionExecutor(tx, block.getCoinbase(), track,
|
||||||
programInvokeFactory, bestBlock);
|
programInvokeFactory, block);
|
||||||
executor.execute();
|
executor.execute();
|
||||||
|
|
||||||
TransactionReceipt receipt = executor.getReceipt();
|
TransactionReceipt receipt = executor.getReceipt();
|
||||||
|
@ -385,7 +391,7 @@ public class BlockchainImpl implements Blockchain {
|
||||||
String worldStateRootHash = Hex.toHexString(repository.getRoot());
|
String worldStateRootHash = Hex.toHexString(repository.getRoot());
|
||||||
if(!blockStateRootHash.equals(worldStateRootHash)){
|
if(!blockStateRootHash.equals(worldStateRootHash)){
|
||||||
|
|
||||||
stateLogger.warn("BLOCK: STATE CONFLICT! block: {} worldstate {} mismatch", block.getNumber(), worldStateRootHash);
|
stateLogger.info("BLOCK: STATE CONFLICT! block: {} worldstate {} mismatch", block.getNumber(), worldStateRootHash);
|
||||||
adminInfo.lostConsensus();
|
adminInfo.lostConsensus();
|
||||||
|
|
||||||
// in case of rollback hard move the root
|
// in case of rollback hard move the root
|
||||||
|
|
|
@ -170,6 +170,25 @@ public class Transaction {
|
||||||
return gasLimit;
|
return gasLimit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public long nonZeroDataBytes(){
|
||||||
|
if (data == null) return 0;
|
||||||
|
int counter = 0;
|
||||||
|
for (int i = 0; i < data.length; ++i){
|
||||||
|
if (data[i] != 0) ++counter;
|
||||||
|
}
|
||||||
|
return counter;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long zeroDataBytes(){
|
||||||
|
if (data == null) return 0;
|
||||||
|
int counter = 0;
|
||||||
|
for (int i = 0; i < data.length; ++i){
|
||||||
|
if (data[i] == 0) ++counter;
|
||||||
|
}
|
||||||
|
return counter;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public byte[] getData() {
|
public byte[] getData() {
|
||||||
if (!parsed) rlpParse();
|
if (!parsed) rlpParse();
|
||||||
return data;
|
return data;
|
||||||
|
|
|
@ -31,21 +31,31 @@ public class TransactionExecutor {
|
||||||
|
|
||||||
private TransactionReceipt receipt;
|
private TransactionReceipt receipt;
|
||||||
private ProgramResult result;
|
private ProgramResult result;
|
||||||
private Block bestBlock;
|
private Block currentBlock;
|
||||||
|
|
||||||
|
|
||||||
public TransactionExecutor(Transaction tx, byte[] coinbase, Repository track,
|
public TransactionExecutor(Transaction tx, byte[] coinbase, Repository track,
|
||||||
ProgramInvokeFactory programInvokeFactory, Block bestBlock) {
|
ProgramInvokeFactory programInvokeFactory, Block currentBlock) {
|
||||||
|
|
||||||
this.tx = tx;
|
this.tx = tx;
|
||||||
this.coinbase = coinbase;
|
this.coinbase = coinbase;
|
||||||
this.track = track;
|
this.track = track;
|
||||||
this.programInvokeFactory = programInvokeFactory;
|
this.programInvokeFactory = programInvokeFactory;
|
||||||
this.bestBlock = bestBlock;
|
this.currentBlock = currentBlock;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* jeff:
|
||||||
|
execution happens like this:
|
||||||
|
create account, transfer value (if any), create a snapshot,
|
||||||
|
run INIT code, if err, rollback to snapshot, if success set return value.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// https://github.com/ethereum/cpp-ethereum/blob/develop/libethereum/Executive.cpp#L55
|
||||||
|
|
||||||
|
|
||||||
public void execute(){
|
public void execute(){
|
||||||
|
|
||||||
|
|
||||||
logger.info("applyTransaction: [{}]", Hex.toHexString(tx.getHash()));
|
logger.info("applyTransaction: [{}]", Hex.toHexString(tx.getHash()));
|
||||||
|
|
||||||
TransactionReceipt receipt = new TransactionReceipt();
|
TransactionReceipt receipt = new TransactionReceipt();
|
||||||
|
@ -70,17 +80,20 @@ public class TransactionExecutor {
|
||||||
|
|
||||||
|
|
||||||
// FIND OUT THE TRANSACTION TYPE
|
// FIND OUT THE TRANSACTION TYPE
|
||||||
byte[] receiverAddress, code = null;
|
byte[] receiverAddress = null;
|
||||||
|
byte[] code = EMPTY_BYTE_ARRAY;
|
||||||
boolean isContractCreation = tx.isContractCreation();
|
boolean isContractCreation = tx.isContractCreation();
|
||||||
if (isContractCreation) {
|
if (isContractCreation) {
|
||||||
receiverAddress = tx.getContractAddress();
|
receiverAddress = tx.getContractAddress();
|
||||||
code = tx.getData(); // init code
|
code = tx.getData(); // init code
|
||||||
|
|
||||||
|
// on CREATE the contract is created event if it will rollback
|
||||||
|
track.addBalance(receiverAddress, BigInteger.ZERO);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
receiverAddress = tx.getReceiveAddress();
|
receiverAddress = tx.getReceiveAddress();
|
||||||
code = track.getCode(receiverAddress);
|
code = track.getCode(receiverAddress);
|
||||||
|
|
||||||
// on invocation the contract is created event if doesn't exist.
|
|
||||||
track.addBalance(receiverAddress, BigInteger.ZERO);
|
|
||||||
if (code != EMPTY_BYTE_ARRAY) {
|
if (code != EMPTY_BYTE_ARRAY) {
|
||||||
if (stateLogger.isDebugEnabled())
|
if (stateLogger.isDebugEnabled())
|
||||||
stateLogger.debug("calling for existing contract: address={}",
|
stateLogger.debug("calling for existing contract: address={}",
|
||||||
|
@ -110,7 +123,6 @@ public class TransactionExecutor {
|
||||||
|
|
||||||
// THE SIMPLE VALUE/BALANCE CHANGE
|
// THE SIMPLE VALUE/BALANCE CHANGE
|
||||||
BigInteger txValue = new BigInteger(1, tx.getValue());
|
BigInteger txValue = new BigInteger(1, tx.getValue());
|
||||||
if (tx.isValueTx()) {
|
|
||||||
if (track.getBalance(senderAddress).compareTo(txValue) >= 0) {
|
if (track.getBalance(senderAddress).compareTo(txValue) >= 0) {
|
||||||
|
|
||||||
track.addBalance(receiverAddress, txValue); // balance will be read again below
|
track.addBalance(receiverAddress, txValue); // balance will be read again below
|
||||||
|
@ -123,12 +135,11 @@ public class TransactionExecutor {
|
||||||
Hex.toHexString(receiverAddress),
|
Hex.toHexString(receiverAddress),
|
||||||
new BigInteger(tx.getValue()));
|
new BigInteger(tx.getValue()));
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// UPDATE THE NONCE
|
// UPDATE THE NONCE
|
||||||
track.increaseNonce(senderAddress);
|
track.increaseNonce(senderAddress);
|
||||||
logger.info("increased tx.nonce to: [{}]", track.getNonce(senderAddress));
|
logger.info("increased nonce to: [{}], addr: [{}]", track.getNonce(senderAddress), Hex.toHexString(senderAddress));
|
||||||
|
|
||||||
// CHARGE FOR GAS
|
// CHARGE FOR GAS
|
||||||
track.addBalance(senderAddress, gasDebit.negate());
|
track.addBalance(senderAddress, gasDebit.negate());
|
||||||
|
@ -162,7 +173,7 @@ public class TransactionExecutor {
|
||||||
}
|
}
|
||||||
|
|
||||||
ProgramInvoke programInvoke =
|
ProgramInvoke programInvoke =
|
||||||
programInvokeFactory.createProgramInvoke(tx, bestBlock, trackTx);
|
programInvokeFactory.createProgramInvoke(tx, currentBlock, trackTx);
|
||||||
|
|
||||||
VM vm = new VM();
|
VM vm = new VM();
|
||||||
Program program = new Program(code, programInvoke);
|
Program program = new Program(code, programInvoke);
|
||||||
|
@ -174,7 +185,7 @@ public class TransactionExecutor {
|
||||||
result = program.getResult();
|
result = program.getResult();
|
||||||
applyProgramResult(result, gasDebit, gasPrice, trackTx,
|
applyProgramResult(result, gasDebit, gasPrice, trackTx,
|
||||||
senderAddress, receiverAddress, coinbase, isContractCreation);
|
senderAddress, receiverAddress, coinbase, isContractCreation);
|
||||||
gasUsed = result.getGasUsed();
|
|
||||||
|
|
||||||
List<LogInfo> logs = result.getLogInfoList();
|
List<LogInfo> logs = result.getLogInfoList();
|
||||||
receipt.setLogInfoList(logs);
|
receipt.setLogInfoList(logs);
|
||||||
|
@ -188,7 +199,9 @@ public class TransactionExecutor {
|
||||||
trackTx.commit();
|
trackTx.commit();
|
||||||
} else {
|
} else {
|
||||||
// REFUND GASDEBIT EXCEPT FOR FEE (500 + 5*TX_NO_ZERO_DATA)
|
// REFUND GASDEBIT EXCEPT FOR FEE (500 + 5*TX_NO_ZERO_DATA)
|
||||||
long dataCost = tx.getData() == null ? 0: tx.getData().length * GasCost.TX_NO_ZERO_DATA;
|
long dataCost = tx.getData() == null ? 0:
|
||||||
|
tx.nonZeroDataBytes() * GasCost.TX_NO_ZERO_DATA +
|
||||||
|
tx.zeroDataBytes() * GasCost.TX_ZERO_DATA;
|
||||||
gasUsed = GasCost.TRANSACTION + dataCost;
|
gasUsed = GasCost.TRANSACTION + dataCost;
|
||||||
|
|
||||||
BigInteger refund = gasDebit.subtract(BigInteger.valueOf(gasUsed).multiply(gasPrice));
|
BigInteger refund = gasDebit.subtract(BigInteger.valueOf(gasUsed).multiply(gasPrice));
|
||||||
|
@ -270,6 +283,18 @@ public class TransactionExecutor {
|
||||||
.debug("saving code of the contract to the db:\n contract={} code={}",
|
.debug("saving code of the contract to the db:\n contract={} code={}",
|
||||||
Hex.toHexString(contractAddress),
|
Hex.toHexString(contractAddress),
|
||||||
Hex.toHexString(bodyCode));
|
Hex.toHexString(bodyCode));
|
||||||
|
|
||||||
|
BigInteger storageCost = gasPrice.multiply( BigInteger.valueOf( bodyCode.length * GasCost.CREATE_DATA_BYTE) );
|
||||||
|
BigInteger balance = repository.getBalance(senderAddress);
|
||||||
|
|
||||||
|
// check if can be charged for the contract data save
|
||||||
|
if (storageCost.compareTo(balance) > 1){
|
||||||
|
bodyCode = EMPTY_BYTE_ARRAY;
|
||||||
|
} else {
|
||||||
|
repository.addBalance(coinbase, storageCost);
|
||||||
|
repository.addBalance(senderAddress, storageCost.negate());
|
||||||
|
}
|
||||||
|
|
||||||
repository.saveCode(contractAddress, bodyCode);
|
repository.saveCode(contractAddress, bodyCode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -72,8 +72,10 @@ public class ContractDetails {
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
int foundIndex = storageKeys.indexOf(key);
|
int foundIndex = storageKeys.indexOf(key);
|
||||||
if (foundIndex != -1)
|
if (foundIndex != -1) {
|
||||||
return storageValues.get(foundIndex);
|
DataWord value = storageValues.get(foundIndex);
|
||||||
|
return value.clone();
|
||||||
|
}
|
||||||
else
|
else
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
|
@ -281,6 +281,12 @@ public class RepositoryDummy implements Repository {
|
||||||
return accountState;
|
return accountState;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isExist(byte[] addr) {
|
||||||
|
return getAccountState(addr) != null;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public byte[] getRoot() {
|
public byte[] getRoot() {
|
||||||
throw new UnsupportedOperationException();
|
throw new UnsupportedOperationException();
|
||||||
|
|
|
@ -409,6 +409,11 @@ public class RepositoryImpl implements Repository {
|
||||||
return accountState;
|
return accountState;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isExist(byte[] addr) {
|
||||||
|
return getAccountState(addr) != null;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void loadAccount(byte[] addr,
|
public void loadAccount(byte[] addr,
|
||||||
HashMap<ByteArrayWrapper, AccountState> cacheAccounts,
|
HashMap<ByteArrayWrapper, AccountState> cacheAccounts,
|
||||||
|
|
|
@ -66,6 +66,22 @@ public class RepositoryTrack implements Repository {
|
||||||
return accountState;
|
return accountState;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isExist(byte[] addr) {
|
||||||
|
|
||||||
|
boolean exist = false;
|
||||||
|
AccountState accountState = cacheAccounts.get(wrap(addr));
|
||||||
|
if (accountState != null && !accountState.isDeleted()) exist = true;
|
||||||
|
|
||||||
|
if (accountState == null){
|
||||||
|
accountState = repository.getAccountState(addr);
|
||||||
|
if (accountState != null && !accountState.isDeleted()) exist = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return exist;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ContractDetails getContractDetails(byte[] addr) {
|
public ContractDetails getContractDetails(byte[] addr) {
|
||||||
|
|
||||||
|
|
|
@ -27,6 +27,14 @@ public interface Repository {
|
||||||
*/
|
*/
|
||||||
public AccountState createAccount(byte[] addr);
|
public AccountState createAccount(byte[] addr);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param addr - account to check
|
||||||
|
* @return - true if account exist,
|
||||||
|
* false otherwise
|
||||||
|
*/
|
||||||
|
public boolean isExist(byte[] addr);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieve an account
|
* Retrieve an account
|
||||||
*
|
*
|
||||||
|
|
|
@ -488,7 +488,7 @@ public class TestRunner {
|
||||||
|
|
||||||
return results;
|
return results;
|
||||||
} finally {
|
} finally {
|
||||||
repository.close();
|
// repository.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -209,8 +209,12 @@ public class EthHandler extends SimpleChannelInboundHandler<EthMessage> {
|
||||||
BlockQueue chainQueue = blockchain.getQueue();
|
BlockQueue chainQueue = blockchain.getQueue();
|
||||||
BigInteger peerTotalDifficulty = new BigInteger(1, msg.getTotalDifficulty());
|
BigInteger peerTotalDifficulty = new BigInteger(1, msg.getTotalDifficulty());
|
||||||
BigInteger highestKnownTotalDifficulty = blockchain.getTotalDifficulty();
|
BigInteger highestKnownTotalDifficulty = blockchain.getTotalDifficulty();
|
||||||
if ( highestKnownTotalDifficulty == null ||
|
|
||||||
peerTotalDifficulty.compareTo(highestKnownTotalDifficulty) > 0) {
|
boolean synced=
|
||||||
|
FastByteComparisons.compareTo(msg.getBestHash(), 0, 32, blockchain.getBestBlockHash(), 0, 32) == 0;
|
||||||
|
|
||||||
|
if ( !synced && (highestKnownTotalDifficulty == null ||
|
||||||
|
peerTotalDifficulty.compareTo(highestKnownTotalDifficulty) > 0)) {
|
||||||
|
|
||||||
logger.info(" Their chain is better: total difficulty : {} vs {}",
|
logger.info(" Their chain is better: total difficulty : {} vs {}",
|
||||||
peerTotalDifficulty.toString(),
|
peerTotalDifficulty.toString(),
|
||||||
|
|
|
@ -30,6 +30,8 @@ public class GasCost {
|
||||||
public static int REFUND_SSTORE = 100;
|
public static int REFUND_SSTORE = 100;
|
||||||
/** Cost 100 gas */
|
/** Cost 100 gas */
|
||||||
public static int CREATE = 100;
|
public static int CREATE = 100;
|
||||||
|
/** Cost 1 gas */
|
||||||
|
public static int CREATE_DATA_BYTE = 5;
|
||||||
/** Cost 20 gas */
|
/** Cost 20 gas */
|
||||||
public static int CALL = 20;
|
public static int CALL = 20;
|
||||||
/** Cost 1 gas */
|
/** Cost 1 gas */
|
||||||
|
|
|
@ -24,6 +24,7 @@ import java.nio.ByteBuffer;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
import static org.ethereum.config.SystemProperties.CONFIG;
|
import static org.ethereum.config.SystemProperties.CONFIG;
|
||||||
|
import static org.ethereum.util.ByteUtil.EMPTY_BYTE_ARRAY;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* www.ethereumJ.com
|
* www.ethereumJ.com
|
||||||
|
@ -57,7 +58,7 @@ public class Program {
|
||||||
|
|
||||||
public Program(byte[] ops, ProgramInvoke invokeData) {
|
public Program(byte[] ops, ProgramInvoke invokeData) {
|
||||||
|
|
||||||
if (ops == null) ops = ByteUtil.EMPTY_BYTE_ARRAY;
|
if (ops == null) ops = EMPTY_BYTE_ARRAY;
|
||||||
this.ops = ops;
|
this.ops = ops;
|
||||||
|
|
||||||
if (invokeData != null) {
|
if (invokeData != null) {
|
||||||
|
@ -358,7 +359,17 @@ public class Program {
|
||||||
|
|
||||||
// 4. CREATE THE CONTRACT OUT OF RETURN
|
// 4. CREATE THE CONTRACT OUT OF RETURN
|
||||||
byte[] code = result.getHReturn().array();
|
byte[] code = result.getHReturn().array();
|
||||||
|
|
||||||
|
long storageCost = code.length * GasCost.CREATE_DATA_BYTE;
|
||||||
|
long afterSpend = invokeData.getGas().longValue() - storageCost - result.getGasUsed();
|
||||||
|
if (afterSpend < 0){
|
||||||
|
track.saveCode(newAddress, EMPTY_BYTE_ARRAY);
|
||||||
|
} else {
|
||||||
|
|
||||||
|
result.spendGas(code.length * GasCost.CREATE_DATA_BYTE);
|
||||||
track.saveCode(newAddress, code);
|
track.saveCode(newAddress, code);
|
||||||
|
}
|
||||||
|
|
||||||
track.commit();
|
track.commit();
|
||||||
|
|
||||||
// IN SUCCESS PUSH THE ADDRESS INTO THE STACK
|
// IN SUCCESS PUSH THE ADDRESS INTO THE STACK
|
||||||
|
@ -529,7 +540,11 @@ public class Program {
|
||||||
}
|
}
|
||||||
|
|
||||||
public byte[] getCodeAt(DataWord address) {
|
public byte[] getCodeAt(DataWord address) {
|
||||||
return invokeData.getRepository().getCode(address.getLast20Bytes());
|
|
||||||
|
byte[] code = invokeData.getRepository().getCode(address.getLast20Bytes());
|
||||||
|
if (code == null) code = ByteUtil.EMPTY_BYTE_ARRAY;
|
||||||
|
|
||||||
|
return code;
|
||||||
}
|
}
|
||||||
|
|
||||||
public DataWord getOwnerAddress() {
|
public DataWord getOwnerAddress() {
|
||||||
|
@ -583,7 +598,7 @@ public class Program {
|
||||||
}
|
}
|
||||||
|
|
||||||
public byte[] getDataCopy(DataWord offset, DataWord length) {
|
public byte[] getDataCopy(DataWord offset, DataWord length) {
|
||||||
if (invokeData == null) return ByteUtil.EMPTY_BYTE_ARRAY;
|
if (invokeData == null) return EMPTY_BYTE_ARRAY;
|
||||||
return invokeData.getDataCopy(offset, length);
|
return invokeData.getDataCopy(offset, length);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -743,6 +758,8 @@ public class Program {
|
||||||
|
|
||||||
public void saveOpTrace(){
|
public void saveOpTrace(){
|
||||||
|
|
||||||
|
if (pc >= ops.length) return;
|
||||||
|
|
||||||
Op op = new Op();
|
Op op = new Op();
|
||||||
op.setPc(pc);
|
op.setPc(pc);
|
||||||
|
|
||||||
|
@ -762,7 +779,7 @@ public class Program {
|
||||||
|
|
||||||
if (!CONFIG.vmTrace()) return;
|
if (!CONFIG.vmTrace()) return;
|
||||||
|
|
||||||
String dir = CONFIG.vmTraceDir() + "/";
|
String dir = CONFIG.databaseDir() + "/" + CONFIG.vmTraceDir() + "/";
|
||||||
|
|
||||||
File dumpFile = new File(System.getProperty("user.dir") + "/" + dir + fileName + ".json");
|
File dumpFile = new File(System.getProperty("user.dir") + "/" + dir + fileName + ".json");
|
||||||
FileWriter fw = null;
|
FileWriter fw = null;
|
||||||
|
|
|
@ -176,10 +176,10 @@ public class ProgramInvokeFactoryImpl implements ProgramInvokeFactory {
|
||||||
Hex.toHexString(address.getLast20Bytes()),
|
Hex.toHexString(address.getLast20Bytes()),
|
||||||
Hex.toHexString(origin.getLast20Bytes()),
|
Hex.toHexString(origin.getLast20Bytes()),
|
||||||
Hex.toHexString(caller.getLast20Bytes()),
|
Hex.toHexString(caller.getLast20Bytes()),
|
||||||
balance.longValue(),
|
balance.toString(),
|
||||||
gasPrice.longValue(),
|
gasPrice.longValue(),
|
||||||
gas.longValue(),
|
gas.longValue(),
|
||||||
callValue.longValue(),
|
callValue.toString(),
|
||||||
data == null ? "": Hex.toHexString(data),
|
data == null ? "": Hex.toHexString(data),
|
||||||
Hex.toHexString(lastHash.getData()),
|
Hex.toHexString(lastHash.getData()),
|
||||||
Hex.toHexString(coinbase.getLast20Bytes()),
|
Hex.toHexString(coinbase.getLast20Bytes()),
|
||||||
|
|
|
@ -5,6 +5,7 @@ import org.ethereum.db.ContractDetails;
|
||||||
|
|
||||||
import static org.ethereum.config.SystemProperties.CONFIG;
|
import static org.ethereum.config.SystemProperties.CONFIG;
|
||||||
|
|
||||||
|
import org.ethereum.util.ByteUtil;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.spongycastle.util.BigIntegers;
|
import org.spongycastle.util.BigIntegers;
|
||||||
|
@ -548,7 +549,7 @@ public class VM {
|
||||||
if (logger.isInfoEnabled())
|
if (logger.isInfoEnabled())
|
||||||
hint = "address: "
|
hint = "address: "
|
||||||
+ Hex.toHexString(address.getLast20Bytes())
|
+ Hex.toHexString(address.getLast20Bytes())
|
||||||
+ " balance: " + balance.longValue();
|
+ " balance: " + balance.toString();
|
||||||
|
|
||||||
program.stackPush(balance);
|
program.stackPush(balance);
|
||||||
program.step();
|
program.step();
|
||||||
|
@ -630,39 +631,34 @@ public class VM {
|
||||||
program.step();
|
program.step();
|
||||||
} break;
|
} break;
|
||||||
case CODECOPY: case EXTCODECOPY: {
|
case CODECOPY: case EXTCODECOPY: {
|
||||||
byte[] fullCode;
|
|
||||||
|
byte[] fullCode = ByteUtil.EMPTY_BYTE_ARRAY;
|
||||||
if (op == OpCode.CODECOPY)
|
if (op == OpCode.CODECOPY)
|
||||||
fullCode = program.getCode();
|
fullCode = program.getCode();
|
||||||
else {
|
|
||||||
|
if (op == OpCode.EXTCODECOPY) {
|
||||||
DataWord address = program.stackPop();
|
DataWord address = program.stackPop();
|
||||||
fullCode = program.getCodeAt(address);
|
fullCode = program.getCodeAt(address);
|
||||||
}
|
}
|
||||||
|
|
||||||
DataWord memOffsetData = program.stackPop();
|
int memOffset = program.stackPop().intValue();
|
||||||
BigInteger codeOffsetData = program.stackPop().value();
|
int codeOffset = program.stackPop().intValue();
|
||||||
BigInteger lengthData = program.stackPop().value();
|
int lengthData = program.stackPop().intValue();
|
||||||
|
|
||||||
/*
|
int sizeToBeCopied =
|
||||||
todo: find out what to do where params are exits the actual code
|
codeOffset + lengthData > fullCode.length ?
|
||||||
if (fullCode == null ||
|
(fullCode.length < codeOffset ? 0 : fullCode.length - codeOffset)
|
||||||
BigInteger.valueOf(fullCode.length).
|
: lengthData;
|
||||||
compareTo(
|
|
||||||
codeOffsetData.add(lengthData)) > 0) {
|
|
||||||
program.stop();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
int length = lengthData.intValue();
|
byte[] codeCopy = new byte[lengthData];
|
||||||
int codeOffset = codeOffsetData.intValue();
|
|
||||||
|
|
||||||
byte[] codeCopy = new byte[fullCode.length - codeOffset];
|
if (codeOffset < fullCode.length)
|
||||||
System.arraycopy(fullCode, codeOffset, codeCopy, 0, fullCode.length - codeOffset);
|
System.arraycopy(fullCode, codeOffset, codeCopy, 0, sizeToBeCopied);
|
||||||
|
|
||||||
if (logger.isInfoEnabled())
|
if (logger.isInfoEnabled())
|
||||||
hint = "code: " + Hex.toHexString(codeCopy);
|
hint = "code: " + Hex.toHexString(codeCopy);
|
||||||
|
|
||||||
program.memorySave(memOffsetData.intValue(), codeCopy);
|
program.memorySave(memOffset, codeCopy);
|
||||||
program.step();
|
program.step();
|
||||||
} break;
|
} break;
|
||||||
case GASPRICE:{
|
case GASPRICE:{
|
||||||
|
@ -969,12 +965,7 @@ public class VM {
|
||||||
DataWord size = program.stackPop();
|
DataWord size = program.stackPop();
|
||||||
|
|
||||||
ByteBuffer hReturn = program.memoryChunk(offset, size);
|
ByteBuffer hReturn = program.memoryChunk(offset, size);
|
||||||
if (hReturn.array().length * 5 <= program.getGas().longValue()){
|
|
||||||
program.spendGas(hReturn.array().length * 5, op.name());
|
|
||||||
program.setHReturn(hReturn);
|
program.setHReturn(hReturn);
|
||||||
} else {
|
|
||||||
program.setHReturn(ByteBuffer.wrap(new byte[]{}));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (logger.isInfoEnabled())
|
if (logger.isInfoEnabled())
|
||||||
hint = "data: " + Hex.toHexString(hReturn.array())
|
hint = "data: " + Hex.toHexString(hReturn.array())
|
||||||
|
|
|
@ -130,7 +130,7 @@ max.blocks.ask = 120
|
||||||
max.blocks.queued = 3000
|
max.blocks.queued = 3000
|
||||||
|
|
||||||
# project version auto copied during build phase
|
# project version auto copied during build phase
|
||||||
project.version = 0.7.9
|
project.version = 0.7.14
|
||||||
|
|
||||||
# hello phrase will be included in
|
# hello phrase will be included in
|
||||||
# the hello message of the peer
|
# the hello message of the peer
|
||||||
|
|
|
@ -3,6 +3,7 @@ package test.ethereum.jsontestsuite;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
import org.ethereum.jsontestsuite.*;
|
import org.ethereum.jsontestsuite.*;
|
||||||
import org.json.simple.JSONObject;
|
import org.json.simple.JSONObject;
|
||||||
|
@ -78,6 +79,40 @@ public class GitHubJSONTestSuite {
|
||||||
Assert.assertTrue(result.isEmpty());
|
Assert.assertTrue(result.isEmpty());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected static void runGitHubJsonStateTest(String json, Set<String> exclude) throws ParseException {
|
||||||
|
Assume.assumeFalse("Online test is not available", json.equals(""));
|
||||||
|
|
||||||
|
JSONParser parser = new JSONParser();
|
||||||
|
JSONObject testSuiteObj = (JSONObject)parser.parse(json);
|
||||||
|
|
||||||
|
StateTestSuite testSuite = new StateTestSuite(testSuiteObj);
|
||||||
|
Collection<StateTestCase> testCollection = testSuite.getAllTests();
|
||||||
|
|
||||||
|
for(StateTestCase testCase : testSuite.getAllTests()){
|
||||||
|
|
||||||
|
String prefix = " ";
|
||||||
|
if (exclude.contains(testCase.getName())) prefix = "[X] ";
|
||||||
|
|
||||||
|
logger.info(prefix + testCase.getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
for (StateTestCase testCase : testCollection){
|
||||||
|
|
||||||
|
if (exclude.contains(testCase.getName())) continue;
|
||||||
|
TestRunner runner = new TestRunner();
|
||||||
|
List<String> result = runner.runTestCase(testCase);
|
||||||
|
|
||||||
|
if (!result.isEmpty()){
|
||||||
|
for (String single : result){
|
||||||
|
logger.info(single);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Assert.assertTrue(result.isEmpty());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
protected static void runGitHubJsonStateTest(String json) throws ParseException {
|
protected static void runGitHubJsonStateTest(String json) throws ParseException {
|
||||||
Assume.assumeFalse("Online test is not available", json.equals(""));
|
Assume.assumeFalse("Online test is not available", json.equals(""));
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,9 @@ import org.junit.FixMethodOrder;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.runners.MethodSorters;
|
import org.junit.runners.MethodSorters;
|
||||||
|
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
|
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
|
||||||
public class GitHubStateTest {
|
public class GitHubStateTest {
|
||||||
|
|
||||||
|
@ -13,11 +16,22 @@ public class GitHubStateTest {
|
||||||
public void stSingleTest() throws ParseException {
|
public void stSingleTest() throws ParseException {
|
||||||
|
|
||||||
String json = JSONReader.loadJSON("StateTests/stSystemOperationsTest.json");
|
String json = JSONReader.loadJSON("StateTests/stSystemOperationsTest.json");
|
||||||
GitHubJSONTestSuite.runGitHubJsonStateTest(json, "CallRecursiveBombLog");
|
GitHubJSONTestSuite.runGitHubJsonStateTest(json, "createNameRegistrator");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void stExample() throws ParseException {
|
public void runWithExcludedTest() throws ParseException {
|
||||||
|
|
||||||
|
Set<String> excluded = new HashSet<>();
|
||||||
|
excluded.add("createNameRegistratorValueTooHigh");
|
||||||
|
|
||||||
|
String json = JSONReader.loadJSON("StateTests/stSystemOperationsTest.json");
|
||||||
|
GitHubJSONTestSuite.runGitHubJsonStateTest(json, excluded);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void stExample() throws ParseException { // [V]
|
||||||
|
|
||||||
String json = JSONReader.loadJSON("StateTests/stExample.json");
|
String json = JSONReader.loadJSON("StateTests/stExample.json");
|
||||||
GitHubJSONTestSuite.runGitHubJsonStateTest(json);
|
GitHubJSONTestSuite.runGitHubJsonStateTest(json);
|
||||||
|
@ -60,7 +74,7 @@ public class GitHubStateTest {
|
||||||
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void stSpecialTest() throws ParseException {
|
public void stSpecialTest() throws ParseException { // [V]
|
||||||
|
|
||||||
String json = JSONReader.loadJSON("StateTests/stSpecialTest.json");
|
String json = JSONReader.loadJSON("StateTests/stSpecialTest.json");
|
||||||
GitHubJSONTestSuite.runGitHubJsonStateTest(json);
|
GitHubJSONTestSuite.runGitHubJsonStateTest(json);
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package test.ethereum.vm;
|
package test.ethereum.vm;
|
||||||
|
|
||||||
|
import junit.framework.Assert;
|
||||||
import org.ethereum.facade.Repository;
|
import org.ethereum.facade.Repository;
|
||||||
import org.ethereum.util.ByteUtil;
|
import org.ethereum.util.ByteUtil;
|
||||||
import org.ethereum.vm.*;
|
import org.ethereum.vm.*;
|
||||||
|
@ -2482,53 +2483,6 @@ public class VMTest {
|
||||||
assertTrue(program.isStopped());
|
assertTrue(program.isStopped());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test // RETURN OP
|
|
||||||
public void testRETURN_5() {
|
|
||||||
|
|
||||||
invoke.setGas(300);
|
|
||||||
|
|
||||||
VM vm = new VM();
|
|
||||||
program =
|
|
||||||
new Program(Hex.decode("7FA0B0C0D0E0F0A1B1C1D1E1F1A2B2C2D2E2F2A3B3C3D3E3F3A4B4C4D4E4F4A1B160005260206010F3"),
|
|
||||||
invoke);
|
|
||||||
String s_expected_1 = "E2F2A3B3C3D3E3F3A4B4C4D4E4F4A1B100000000000000000000000000000000";
|
|
||||||
|
|
||||||
vm.step(program);
|
|
||||||
vm.step(program);
|
|
||||||
vm.step(program);
|
|
||||||
vm.step(program);
|
|
||||||
vm.step(program);
|
|
||||||
vm.step(program);
|
|
||||||
|
|
||||||
assertEquals(s_expected_1, Hex.toHexString(program.getResult().getHReturn().array()).toUpperCase());
|
|
||||||
assertEquals(132, program.getGas().longValue());
|
|
||||||
assertTrue(program.isStopped());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test // RETURN OP
|
|
||||||
public void testRETURN_6() {
|
|
||||||
|
|
||||||
invoke.setGas(100);
|
|
||||||
|
|
||||||
VM vm = new VM();
|
|
||||||
program =
|
|
||||||
new Program(Hex.decode("7FA0B0C0D0E0F0A1B1C1D1E1F1A2B2C2D2E2F2A3B3C3D3E3F3A4B4C4D4E4F4A1B160005260206010F3"),
|
|
||||||
invoke);
|
|
||||||
|
|
||||||
vm.step(program);
|
|
||||||
vm.step(program);
|
|
||||||
vm.step(program);
|
|
||||||
vm.step(program);
|
|
||||||
vm.step(program);
|
|
||||||
vm.step(program);
|
|
||||||
|
|
||||||
assertArrayEquals("".getBytes(), program.getResult().getHReturn().array());
|
|
||||||
assertEquals(92, program.getGas().longValue());
|
|
||||||
assertTrue(program.isStopped());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@Test // CODECOPY OP
|
@Test // CODECOPY OP
|
||||||
public void testCODECOPY_1() {
|
public void testCODECOPY_1() {
|
||||||
|
@ -2570,6 +2524,10 @@ public class VMTest {
|
||||||
@Test // CODECOPY OP
|
@Test // CODECOPY OP
|
||||||
public void testCODECOPY_3() {
|
public void testCODECOPY_3() {
|
||||||
|
|
||||||
|
// cost for that:
|
||||||
|
// 94 - data copied
|
||||||
|
// 95 - new bytes allocated
|
||||||
|
|
||||||
VM vm = new VM();
|
VM vm = new VM();
|
||||||
program =
|
program =
|
||||||
new Program(Hex.decode("605E60076000396000605f556014600054601e60205463abcddcba6040545b51602001600a5254516040016014525451606001601e5254516080016028525460a052546016604860003960166000f26000603f556103e75660005460005360200235"),
|
new Program(Hex.decode("605E60076000396000605f556014600054601e60205463abcddcba6040545b51602001600a5254516040016014525451606001601e5254516080016028525460a052546016604860003960166000f26000603f556103e75660005460005360200235"),
|
||||||
|
@ -2580,7 +2538,7 @@ public class VMTest {
|
||||||
vm.step(program);
|
vm.step(program);
|
||||||
vm.step(program);
|
vm.step(program);
|
||||||
|
|
||||||
assertTrue(program.isStopped());
|
assertEquals( 10, program.getResult().getGasUsed() );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test // CODECOPY OP
|
@Test // CODECOPY OP
|
||||||
|
@ -2596,13 +2554,9 @@ public class VMTest {
|
||||||
vm.step(program);
|
vm.step(program);
|
||||||
vm.step(program);
|
vm.step(program);
|
||||||
|
|
||||||
assertTrue(program.isStopped());
|
assertEquals( 10, program.getResult().getGasUsed() );
|
||||||
}
|
}
|
||||||
|
|
||||||
// DataWord memOffsetData
|
|
||||||
// DataWord codeOffsetData
|
|
||||||
// DataWord lengthData
|
|
||||||
|
|
||||||
|
|
||||||
@Test // CODECOPY OP
|
@Test // CODECOPY OP
|
||||||
public void testCODECOPY_5() {
|
public void testCODECOPY_5() {
|
||||||
|
@ -2685,34 +2639,19 @@ public class VMTest {
|
||||||
new Program(Hex.decode("605E6007600073471FD3AD3E9EEADEEC4608B92D16CE6B500704CC3C6000605f556014600054601e60205463abcddcba6040545b51602001600a5254516040016014525451606001601e5254516080016028525460a052546016604860003960166000f26000603f556103e75660005460005360200235"),
|
new Program(Hex.decode("605E6007600073471FD3AD3E9EEADEEC4608B92D16CE6B500704CC3C6000605f556014600054601e60205463abcddcba6040545b51602001600a5254516040016014525451606001601e5254516080016028525460a052546016604860003960166000f26000603f556103e75660005460005360200235"),
|
||||||
invoke);
|
invoke);
|
||||||
|
|
||||||
|
String m_expected_1 = "6000605F556014600054601E60205463ABCDDCBA6040545B51602001600A5254516040016014525451606001601E5254516080016028525460A052546016604860003960166000F26000603F556103E756600054600053602002350000000000";
|
||||||
|
|
||||||
vm.step(program);
|
vm.step(program);
|
||||||
vm.step(program);
|
vm.step(program);
|
||||||
vm.step(program);
|
vm.step(program);
|
||||||
vm.step(program);
|
vm.step(program);
|
||||||
vm.step(program);
|
vm.step(program);
|
||||||
|
|
||||||
assertTrue(program.isStopped());
|
assertEquals(m_expected_1, Hex.toHexString(program.getMemory().array()).toUpperCase());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test // EXTCODECOPY OP
|
@Test // EXTCODECOPY OP
|
||||||
public void testEXTCODECOPY_4() {
|
public void testEXTCODECOPY_4() {
|
||||||
|
|
||||||
VM vm = new VM();
|
|
||||||
program =
|
|
||||||
new Program(Hex.decode("605E6007600073471FD3AD3E9EEADEEC4608B92D16CE6B500704CC3C6000605f556014600054601e60205463abcddcba6040545b51602001600a5254516040016014525451606001601e5254516080016028525460a052546016604860003960166000f26000603f556103e756600054600053602002351234"),
|
|
||||||
invoke);
|
|
||||||
|
|
||||||
vm.step(program);
|
|
||||||
vm.step(program);
|
|
||||||
vm.step(program);
|
|
||||||
vm.step(program);
|
|
||||||
vm.step(program);
|
|
||||||
|
|
||||||
assertTrue(program.isStopped());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test // EXTCODECOPY OP
|
|
||||||
public void testEXTCODECOPY_5() {
|
|
||||||
VM vm = new VM();
|
VM vm = new VM();
|
||||||
program =
|
program =
|
||||||
new Program(Hex.decode("611234600054615566602054603E6000602073471FD3AD3E9EEADEEC4608B92D16CE6B500704CC3C6000605f556014600054601e60205463abcddcba6040545b51602001600a5254516040016014525451606001601e5254516080016028525460a052546016604860003960166000f26000603f556103e756600054600053602002351234"),
|
new Program(Hex.decode("611234600054615566602054603E6000602073471FD3AD3E9EEADEEC4608B92D16CE6B500704CC3C6000605f556014600054601e60205463abcddcba6040545b51602001600a5254516040016014525451606001601e5254516080016028525460a052546016604860003960166000f26000603f556103e756600054600053602002351234"),
|
||||||
|
@ -2735,7 +2674,7 @@ public class VMTest {
|
||||||
|
|
||||||
|
|
||||||
@Test(expected=StackTooSmallException.class) // EXTCODECOPY OP mal
|
@Test(expected=StackTooSmallException.class) // EXTCODECOPY OP mal
|
||||||
public void testEXTCODECOPY_6() {
|
public void testEXTCODECOPY_5() {
|
||||||
VM vm = new VM();
|
VM vm = new VM();
|
||||||
program =
|
program =
|
||||||
new Program(Hex.decode("605E600773471FD3AD3E9EEADEEC4608B92D16CE6B500704CC3C"),
|
new Program(Hex.decode("605E600773471FD3AD3E9EEADEEC4608B92D16CE6B500704CC3C"),
|
||||||
|
|
Loading…
Reference in New Issue