Validate JUMPDEST by pre-compile + tweak injection of blockStore by the new interface
This commit is contained in:
parent
59833f3fd6
commit
48b27d38ec
|
@ -1,6 +1,6 @@
|
|||
package org.ethereum.core;
|
||||
|
||||
import org.ethereum.db.BlockStoreImpl;
|
||||
import org.ethereum.db.BlockStore;
|
||||
import org.ethereum.facade.Blockchain;
|
||||
import org.ethereum.facade.Repository;
|
||||
import org.ethereum.listener.EthereumListener;
|
||||
|
@ -9,12 +9,9 @@ import org.ethereum.net.BlockQueue;
|
|||
import org.ethereum.net.server.ChannelManager;
|
||||
import org.ethereum.util.AdvancedDeviceUtils;
|
||||
import org.ethereum.vm.ProgramInvokeFactory;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import org.spongycastle.util.encoders.Hex;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.FileSystemUtils;
|
||||
|
@ -23,9 +20,7 @@ import java.io.BufferedWriter;
|
|||
import java.io.File;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
|
||||
import java.math.BigInteger;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
@ -79,7 +74,7 @@ public class BlockchainImpl implements Blockchain {
|
|||
private Repository track;
|
||||
|
||||
@Autowired
|
||||
private BlockStoreImpl blockStore;
|
||||
private BlockStore blockStore;
|
||||
|
||||
private Block bestBlock;
|
||||
private BigInteger totalDifficulty = BigInteger.ZERO;
|
||||
|
|
|
@ -1,6 +1,11 @@
|
|||
package org.ethereum.db;
|
||||
|
||||
import org.ethereum.core.Block;
|
||||
import org.ethereum.core.TransactionReceipt;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author: Roman Mandeleil
|
||||
|
@ -10,4 +15,38 @@ import org.ethereum.core.Block;
|
|||
public interface BlockStore {
|
||||
|
||||
public byte[] getBlockHashByNumber(long blockNumber);
|
||||
|
||||
@Transactional(readOnly = true)
|
||||
Block getBlockByNumber(long blockNumber);
|
||||
|
||||
@Transactional(readOnly = true)
|
||||
Block getBlockByHash(byte[] hash);
|
||||
|
||||
@Transactional(readOnly = true)
|
||||
@SuppressWarnings("unchecked")
|
||||
List<byte[]> getListOfHashesStartFrom(byte[] hash, int qty);
|
||||
|
||||
@Transactional
|
||||
void deleteBlocksSince(long number);
|
||||
|
||||
@Transactional
|
||||
void saveBlock(Block block, List<TransactionReceipt> receipts);
|
||||
|
||||
@Transactional(readOnly = true)
|
||||
BigInteger getTotalDifficultySince(long number);
|
||||
|
||||
@Transactional(readOnly = true)
|
||||
BigInteger getTotalDifficulty();
|
||||
|
||||
@Transactional(readOnly = true)
|
||||
Block getBestBlock();
|
||||
|
||||
@Transactional(readOnly = true)
|
||||
@SuppressWarnings("unchecked")
|
||||
List<Block> getAllBlocks();
|
||||
|
||||
@Transactional
|
||||
void reset();
|
||||
|
||||
TransactionReceipt getTransactionReceiptByHash(byte[] hash);
|
||||
}
|
||||
|
|
|
@ -1,8 +1,13 @@
|
|||
package org.ethereum.db;
|
||||
|
||||
import org.ethereum.core.Block;
|
||||
import org.ethereum.core.TransactionReceipt;
|
||||
import org.ethereum.crypto.HashUtil;
|
||||
import org.ethereum.util.ByteUtil;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author: Roman Mandeleil
|
||||
* Created on: 08/01/2015 17:33
|
||||
|
@ -16,4 +21,59 @@ public class BlockStoreDummy implements BlockStore{
|
|||
byte[] data = String.valueOf(blockNumber).getBytes();
|
||||
return HashUtil.sha3(data);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Block getBlockByNumber(long blockNumber) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Block getBlockByHash(byte[] hash) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<byte[]> getListOfHashesStartFrom(byte[] hash, int qty) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteBlocksSince(long number) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveBlock(Block block, List<TransactionReceipt> receipts) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public BigInteger getTotalDifficultySince(long number) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BigInteger getTotalDifficulty() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Block getBestBlock() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Block> getAllBlocks() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reset() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public TransactionReceipt getTransactionReceiptByHash(byte[] hash) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,7 +21,7 @@ import java.util.List;
|
|||
* @author Roman Mandeleil
|
||||
* @since 12.11.2014
|
||||
*/
|
||||
@Repository
|
||||
@Repository("blockStore")
|
||||
@Transactional(propagation = Propagation.SUPPORTS)
|
||||
public class BlockStoreImpl implements BlockStore{
|
||||
|
||||
|
@ -31,6 +31,9 @@ public class BlockStoreImpl implements BlockStore{
|
|||
@Autowired
|
||||
ApplicationContext ctx;
|
||||
|
||||
public BlockStoreImpl() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] getBlockHashByNumber(long blockNumber) {
|
||||
|
||||
|
@ -39,6 +42,7 @@ public class BlockStoreImpl implements BlockStore{
|
|||
return ByteUtil.EMPTY_BYTE_ARRAY;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(readOnly = true)
|
||||
public Block getBlockByNumber(long blockNumber) {
|
||||
|
||||
|
@ -52,6 +56,7 @@ public class BlockStoreImpl implements BlockStore{
|
|||
return new Block(vo.rlp);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(readOnly = true)
|
||||
public Block getBlockByHash(byte[] hash) {
|
||||
|
||||
|
@ -65,6 +70,7 @@ public class BlockStoreImpl implements BlockStore{
|
|||
return new Block(vo.rlp);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(readOnly = true)
|
||||
@SuppressWarnings("unchecked")
|
||||
public List<byte[]> getListOfHashesStartFrom(byte[] hash, int qty) {
|
||||
|
@ -87,6 +93,7 @@ public class BlockStoreImpl implements BlockStore{
|
|||
return hashes;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public void deleteBlocksSince(long number) {
|
||||
|
||||
|
@ -97,6 +104,7 @@ public class BlockStoreImpl implements BlockStore{
|
|||
}
|
||||
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public void saveBlock(Block block, List<TransactionReceipt> receipts) {
|
||||
|
||||
|
@ -115,6 +123,7 @@ public class BlockStoreImpl implements BlockStore{
|
|||
sessionFactory.getCurrentSession().persist(blockVO);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(readOnly = true)
|
||||
public BigInteger getTotalDifficultySince(long number) {
|
||||
|
||||
|
@ -127,6 +136,7 @@ public class BlockStoreImpl implements BlockStore{
|
|||
}
|
||||
|
||||
|
||||
@Override
|
||||
@Transactional(readOnly = true)
|
||||
public BigInteger getTotalDifficulty() {
|
||||
|
||||
|
@ -137,6 +147,7 @@ public class BlockStoreImpl implements BlockStore{
|
|||
}
|
||||
|
||||
|
||||
@Override
|
||||
@Transactional(readOnly = true)
|
||||
public Block getBestBlock() {
|
||||
|
||||
|
@ -151,6 +162,7 @@ public class BlockStoreImpl implements BlockStore{
|
|||
return new Block(vo.rlp);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(readOnly = true)
|
||||
@SuppressWarnings("unchecked")
|
||||
public List<Block> getAllBlocks() {
|
||||
|
@ -166,12 +178,14 @@ public class BlockStoreImpl implements BlockStore{
|
|||
return blocks;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public void reset() {
|
||||
sessionFactory.getCurrentSession().
|
||||
createQuery("delete from BlockVO").executeUpdate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public TransactionReceipt getTransactionReceiptByHash(byte[] hash) {
|
||||
|
||||
List result = sessionFactory.getCurrentSession().
|
||||
|
|
|
@ -6,6 +6,7 @@ import org.ethereum.core.Transaction;
|
|||
import org.ethereum.core.TransactionReceipt;
|
||||
import org.ethereum.core.Wallet;
|
||||
import org.ethereum.crypto.HashUtil;
|
||||
import org.ethereum.db.BlockStore;
|
||||
import org.ethereum.db.BlockStoreImpl;
|
||||
import org.ethereum.facade.Blockchain;
|
||||
import org.ethereum.facade.Repository;
|
||||
|
@ -63,7 +64,7 @@ public class WorldManager {
|
|||
private PeerDiscovery peerDiscovery;
|
||||
|
||||
@Autowired
|
||||
private BlockStoreImpl blockStore;
|
||||
private BlockStore blockStore;
|
||||
|
||||
@Autowired
|
||||
private ChannelManager channelManager;
|
||||
|
|
|
@ -27,11 +27,7 @@ import java.math.BigInteger;
|
|||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Stack;
|
||||
import java.util.*;
|
||||
|
||||
import static org.ethereum.config.SystemProperties.CONFIG;
|
||||
import static org.ethereum.util.ByteUtil.EMPTY_BYTE_ARRAY;
|
||||
|
@ -71,6 +67,8 @@ public class Program {
|
|||
byte previouslyExecutedOp = 0;
|
||||
boolean stopped = false;
|
||||
|
||||
private Set<Integer> jumpdest = new HashSet<>();
|
||||
|
||||
ProgramInvoke invokeData;
|
||||
|
||||
public Program(byte[] ops, ProgramInvoke invokeData) {
|
||||
|
@ -83,6 +81,7 @@ public class Program {
|
|||
this.programAddress = invokeData.getOwnerAddress();
|
||||
this.invokeHash = invokeData.hashCode();
|
||||
this.result.setRepository(invokeData.getRepository());
|
||||
precompile();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -856,6 +855,21 @@ public class Program {
|
|||
return programTrace;
|
||||
}
|
||||
|
||||
public void precompile(){
|
||||
for (int i = 0; i < ops.length; ++i){
|
||||
|
||||
OpCode op = OpCode.code(ops[i]);
|
||||
if (op == null) continue;
|
||||
|
||||
if (op.equals(OpCode.JUMPDEST)) jumpdest.add(i);
|
||||
|
||||
if (op.asInt() >= OpCode.PUSH1.asInt() && op.asInt() <= OpCode.PUSH32.asInt()){
|
||||
i += op.asInt() - OpCode.PUSH1.asInt() + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static String stringify(byte[] code, int index, String result) {
|
||||
if (code == null || code.length == 0)
|
||||
return result;
|
||||
|
@ -889,6 +903,10 @@ public class Program {
|
|||
this.listener = listener;
|
||||
}
|
||||
|
||||
public void vallidateJumpDest(int nextPC) {
|
||||
if (!jumpdest.contains(nextPC)) throw new BadJumpDestinationException();
|
||||
}
|
||||
|
||||
public interface ProgramListener {
|
||||
public void output(String out);
|
||||
}
|
||||
|
|
|
@ -30,9 +30,6 @@ public class ProgramInvokeFactoryImpl implements ProgramInvokeFactory {
|
|||
@Autowired
|
||||
private Blockchain blockchain;
|
||||
|
||||
@Autowired
|
||||
private BlockStoreImpl blockStore;
|
||||
|
||||
|
||||
// Invocation by the wire tx
|
||||
@Override
|
||||
|
|
|
@ -896,8 +896,7 @@ public class VM {
|
|||
case JUMP: {
|
||||
DataWord pos = program.stackPop();
|
||||
int nextPC = pos.intValue(); // possible overflow
|
||||
if (nextPC != 0 && program.getOp(nextPC) != OpCode.JUMPDEST.val())
|
||||
throw program.new BadJumpDestinationException();
|
||||
program.vallidateJumpDest(nextPC);
|
||||
|
||||
if (logger.isInfoEnabled())
|
||||
hint = "~> " + nextPC;
|
||||
|
@ -913,8 +912,7 @@ public class VM {
|
|||
if (!cond.isZero()) {
|
||||
|
||||
int nextPC = pos.intValue(); // possible overflow
|
||||
if (nextPC != 0 && program.getOp(nextPC) != OpCode.JUMPDEST.val())
|
||||
throw program.new BadJumpDestinationException();
|
||||
program.vallidateJumpDest(nextPC);
|
||||
|
||||
if (logger.isInfoEnabled())
|
||||
hint = "~> " + nextPC;
|
||||
|
|
|
@ -399,14 +399,15 @@ public class VMCustomTest {
|
|||
}
|
||||
}
|
||||
|
||||
@Test // PREVHASH OP
|
||||
public void testPREVHASH_1() {
|
||||
@Test // BLOCKHASH OP
|
||||
public void testBLOCKHASH_1() {
|
||||
|
||||
VM vm = new VM();
|
||||
program =
|
||||
new Program(Hex.decode("40"), invoke);
|
||||
String s_expected_1 = "961CB117ABA86D1E596854015A1483323F18883C2D745B0BC03E87F146D2BB1C";
|
||||
new Program(Hex.decode("600140"), invoke);
|
||||
String s_expected_1 = "C89EFDAA54C0F20C7ADF612882DF0950F5A951637E0307CDCB4C672F298B8BC6";
|
||||
|
||||
vm.step(program);
|
||||
vm.step(program);
|
||||
|
||||
DataWord item1 = program.stackPop();
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package test.ethereum.vm;
|
||||
|
||||
import jdk.nashorn.internal.ir.annotations.Ignore;
|
||||
import org.ethereum.facade.Repository;
|
||||
import org.ethereum.util.ByteUtil;
|
||||
import org.ethereum.vm.DataWord;
|
||||
|
@ -2732,6 +2733,7 @@ public class VMTest {
|
|||
assertEquals(s_expected_1, Hex.toHexString(item1.getData()).toUpperCase());
|
||||
}
|
||||
|
||||
@Ignore // todo: test is not testing EXTCODESIZE
|
||||
@Test // EXTCODESIZE OP
|
||||
public void testEXTCODESIZE_1() {
|
||||
VM vm = new VM();
|
||||
|
|
Loading…
Reference in New Issue