Conflicts:
	src/main/java/org/ethereum/core/Block.java
This commit is contained in:
romanman 2014-05-17 09:54:37 +03:00
commit abafc215e8
19 changed files with 307 additions and 130 deletions

View File

@ -1,6 +1,7 @@
package org.ethereum.core;
import org.ethereum.crypto.HashUtil;
import org.ethereum.util.RLP;
import org.ethereum.util.RLPElement;
import org.ethereum.util.RLPItem;
import org.ethereum.util.RLPList;
@ -24,8 +25,7 @@ public class Block {
/* A scalar value equal to the current limit of gas expenditure per block */
private static int GAS_LIMIT = (int) Math.pow(10, 6);
private RLPList rawData;
private byte[] encodedBlock;
private byte[] rlpEncoded;
private boolean parsed = false;
private byte[] hash;
@ -72,19 +72,15 @@ public class Block {
private List<Transaction> transactionsList = new ArrayList<Transaction>();
private List<Block> uncleList = new ArrayList<Block>();
public Block(RLPList rawData) {
this.rawData = rawData;
public Block(byte[] rawData) {
this.rlpEncoded = rawData;
this.parsed = false;
}
public Block(byte[] encodedBlock) {
this.encodedBlock = encodedBlock;
}
public Block(byte[] parentHash, byte[] unclesHash, byte[] coinbase,
byte[] stateRoot, byte[] txTrieRoot, byte[] difficulty,
long timestamp, long number, long minGasPrice, long gasLimit,
long gasUsed, byte[] extraData, byte[] nonce,
long number, long minGasPrice, long gasLimit, long gasUsed,
long timestamp, byte[] extraData, byte[] nonce,
List<Transaction> transactionsList, List<Block> uncleList) {
this.parentHash = parentHash;
this.unclesHash = unclesHash;
@ -92,11 +88,11 @@ public class Block {
this.stateRoot = stateRoot;
this.txTrieRoot = txTrieRoot;
this.difficulty = difficulty;
this.timestamp = timestamp;
this.number = number;
this.minGasPrice = minGasPrice;
this.gasLimit = gasLimit;
this.gasUsed = gasUsed;
this.timestamp = timestamp;
this.extraData = extraData;
this.nonce = nonce;
this.transactionsList = transactionsList;
@ -105,47 +101,49 @@ public class Block {
}
// [parent_hash, uncles_hash, coinbase, state_root, tx_trie_root,
// difficulty, timestamp, number, minGasPrice, gasLimit, gasUsed,
// difficulty, number, minGasPrice, gasLimit, gasUsed, timestamp,
// extradata, nonce]
private void parseRLP() {
RLPList params = (RLPList) RLP.decode2(rlpEncoded);
RLPList params = (RLPList) rawData.get(0);
this.hash = HashUtil.sha3(rlpEncoded);
this.hash = HashUtil.sha3(rawData.getRLPData());
RLPList block = (RLPList) params.get(0);
RLPList header = (RLPList) block.get(0);
this.parentHash = ((RLPItem) header.get(0)).getRLPData();
this.unclesHash = ((RLPItem) header.get(1)).getRLPData();
this.coinbase = ((RLPItem) header.get(2)).getRLPData();
this.stateRoot = ((RLPItem) header.get(3)).getRLPData();
this.txTrieRoot = ((RLPItem) header.get(4)).getRLPData();
this.difficulty = ((RLPItem) header.get(5)).getRLPData();
this.parentHash = ((RLPItem) params.get(0)).getData();
this.unclesHash = ((RLPItem) params.get(1)).getData();
this.coinbase = ((RLPItem) params.get(2)).getData();
this.stateRoot = ((RLPItem) params.get(3)).getData();
this.txTrieRoot = ((RLPItem) params.get(4)).getData();
this.difficulty = ((RLPItem) params.get(5)).getData();
byte[] tsBytes = ((RLPItem) params.get(6)).getData();
byte[] nrBytes = ((RLPItem) params.get(7)).getData();
byte[] gpBytes = ((RLPItem) params.get(8)).getData();
byte[] glBytes = ((RLPItem) params.get(9)).getData();
byte[] guBytes = ((RLPItem) params.get(10)).getData();
this.timestamp = tsBytes == null ? 0 : (new BigInteger(tsBytes)).longValue();
byte[] nrBytes = ((RLPItem) header.get(6)).getRLPData();
byte[] gpBytes = ((RLPItem) header.get(7)).getRLPData();
byte[] glBytes = ((RLPItem) header.get(8)).getRLPData();
byte[] guBytes = ((RLPItem) header.get(9)).getRLPData();
byte[] tsBytes = ((RLPItem) header.get(10)).getRLPData();
this.number = nrBytes == null ? 0 : (new BigInteger(nrBytes)).longValue();
this.minGasPrice = gpBytes == null ? 0 : (new BigInteger(gpBytes)).longValue();
this.gasLimit = glBytes == null ? 0 : (new BigInteger(glBytes)).longValue();
this.gasUsed = guBytes == null ? 0 : (new BigInteger(guBytes)).longValue();
this.timestamp = tsBytes == null ? 0 : (new BigInteger(tsBytes)).longValue();
this.extraData = ((RLPItem) params.get(11)).getData();
this.nonce = ((RLPItem) params.get(12)).getData();
this.extraData = ((RLPItem) header.get(11)).getRLPData();
this.nonce = ((RLPItem) header.get(12)).getRLPData();
// parse transactions
RLPList transactions = (RLPList) rawData.get(1);
RLPList transactions = (RLPList) block.get(1);
for (RLPElement rlpTx : transactions){
Transaction tx = new Transaction((RLPList)rlpTx);
Transaction tx = new Transaction(rlpTx.getRLPData());
this.transactionsList.add(tx);
}
// parse uncles
RLPList uncleBlocks = (RLPList) rawData.get(2);
RLPList uncleBlocks = (RLPList) block.get(2);
for (RLPElement rawUncle : uncleBlocks){
Block blockData = new Block((RLPList)rawUncle);
Block blockData = new Block(rawUncle.getRLPData());
this.uncleList.add(blockData);
}
this.parsed = true;
@ -153,7 +151,7 @@ public class Block {
public byte[] getHash(){
if (!parsed) parseRLP();
return hash;
return HashUtil.sha3(this.getEncoded());
}
public Block getParent() {
@ -197,18 +195,22 @@ public class Block {
}
public long getNumber() {
if (!parsed) parseRLP();
return number;
}
public long getMinGasPrice() {
if (!parsed) parseRLP();
return minGasPrice;
}
public long getGasLimit() {
if (!parsed) parseRLP();
return gasLimit;
}
public long getGasUsed() {
if (!parsed) parseRLP();
return gasUsed;
}
@ -239,7 +241,7 @@ public class Block {
}
// [parent_hash, uncles_hash, coinbase, state_root, tx_trie_root,
// difficulty, timestamp, number, minGasPrice, gasLimit, gasUsed,
// difficulty, number, minGasPrice, gasLimit, gasUsed, timestamp,
// extradata, nonce]
@Override
public String toString() {
@ -290,11 +292,39 @@ public class Block {
}
public byte[] getEncoded() {
if (this.rawData.getRLPData() == null) parseRLP();
return this.rawData.getRLPData();
}
if(rlpEncoded == null) {
// TODO: Alternative clean way to encode, using RLP.encode() after it's optimized
// Object[] header = new Object[] { parentHash, unclesHash, coinbase,
// stateRoot, txTrieRoot, difficulty, number, minGasPrice,
// gasLimit, gasUsed, timestamp, extraData, nonce };
// Object[] transactions = this.getTransactionsList().toArray();
// Object[] uncles = this.getUncleList().toArray();
// return RLP.encode(new Object[] { header, transactions, uncles });
byte[] parentHash = RLP.encodeElement(this.parentHash);
byte[] unclesHash = RLP.encodeElement(this.unclesHash);
byte[] coinbase = RLP.encodeElement(this.coinbase);
byte[] stateRoot = RLP.encodeElement(this.stateRoot);
byte[] txTrieRoot = RLP.encodeElement(this.txTrieRoot);
byte[] difficulty = RLP.encodeElement(this.difficulty);
byte[] number = RLP.encodeBigInteger(BigInteger.valueOf(this.number));
byte[] minGasPrice = RLP.encodeBigInteger(BigInteger.valueOf(this.minGasPrice));
byte[] gasLimit = RLP.encodeBigInteger(BigInteger.valueOf(this.gasLimit));
byte[] gasUsed = RLP.encodeBigInteger(BigInteger.valueOf(this.gasUsed));
byte[] timestamp = RLP.encodeBigInteger(BigInteger.valueOf(this.timestamp));
byte[] extraData = RLP.encodeElement(this.extraData);
byte[] nonce = RLP.encodeElement(this.nonce);
public byte[] hash() {
return HashUtil.sha3(this.getEncoded());
byte[] header = RLP.encodeList(parentHash, unclesHash, coinbase,
stateRoot, txTrieRoot, difficulty, number,
minGasPrice, gasLimit, gasUsed, timestamp, extraData, nonce);
byte[] transactions = RLP.encodeList();
byte[] uncles = RLP.encodeList();
this.rlpEncoded = RLP.encodeList(header, transactions, uncles);
}
return rlpEncoded;
}
}

View File

@ -0,0 +1,22 @@
package org.ethereum.core;
import java.math.BigDecimal;
import java.math.BigInteger;
public enum Denomination {
WEI(BigInteger.ONE),
SZABO(BigDecimal.valueOf(Math.pow(10, 12)).toBigInteger()),
FINNY(BigDecimal.valueOf(Math.pow(10, 15)).toBigInteger()),
ETHER(BigDecimal.valueOf(Math.pow(10, 18)).toBigInteger());
private BigInteger amount;
private Denomination(BigInteger value) {
this.amount = value;
}
public BigInteger getDenomination() {
return amount;
}
}

View File

@ -1,11 +1,17 @@
package org.ethereum.core;
import java.math.BigInteger;
import org.ethereum.crypto.ECKey.ECDSASignature;
import org.ethereum.crypto.ECKey;
import org.ethereum.crypto.HashUtil;
import org.ethereum.util.RLP;
import org.ethereum.util.RLPItem;
import org.ethereum.util.RLPList;
import org.ethereum.util.Utils;
import org.spongycastle.util.encoders.Hex;
import edu.emory.mathcs.backport.java.util.Arrays;
/**
* A transaction (formally, T ) is a single cryptographically
@ -17,7 +23,7 @@ import org.ethereum.util.Utils;
*/
public class Transaction {
private RLPList rawData;
private byte[] rlpEncoded;
private boolean parsed = false;
/* creation contract tx
@ -44,8 +50,7 @@ public class Transaction {
* to the state or transaction list consumes some gas. */
private byte[] gasLimit;
/* An unlimited size byte array specifying
* either input [data] of the message call
* or the [body] for a new contract */
* input [data] of the message call */
private byte[] data;
/* Initialisation code for a new contract */
private byte[] init;
@ -53,60 +58,72 @@ public class Transaction {
* (including public key recovery bits) */
private ECDSASignature signature;
public Transaction(RLPList rawData) {
this.rawData = rawData;
public Transaction(byte[] rawData) {
System.out.println("Transaction created from RLP: " + Hex.toHexString(rawData));
this.rlpEncoded = rawData;
parsed = false;
}
public Transaction(byte[] nonce, byte[] value, byte[] recieveAddress, byte[] gasPrice, byte[] gas, byte[] data, byte v, byte[] r, byte[] s) {
public Transaction(byte[] nonce, byte[] value, byte[] recieveAddress, byte[] gasPrice, byte[] gas, byte[] data) {
this.nonce = nonce;
this.value = value;
this.receiveAddress = recieveAddress;
this.gasPrice = gasPrice;
this.gasLimit = gas;
this.data = data;
this.signature = ECDSASignature.fromComponents(r, s, v);
if(recieveAddress == null) {
this.init = data;
} else {
this.data = data;
}
parsed = true;
}
public void rlpParse(){
RLPList params = (RLPList) rawData.get(0);
RLPList decodedTxList = RLP.decode2(rlpEncoded);
RLPList transaction = (RLPList) ((RLPList) decodedTxList.get(0)).get(0);
this.hash = HashUtil.sha3(rawData.getRLPData());
this.nonce = ((RLPItem) params.get(0)).getData();
this.value = ((RLPItem) params.get(1)).getData();
this.receiveAddress = ((RLPItem) params.get(2)).getData();
this.gasPrice = ((RLPItem) params.get(3)).getData();
this.gasLimit = ((RLPItem) params.get(4)).getData();
this.data = ((RLPItem) params.get(5)).getData();
this.hash = HashUtil.sha3(rlpEncoded);
/* Temporary order for an RLP encoded transaction in cpp client */
this.nonce = ((RLPItem) transaction.get(0)).getRLPData();
this.gasPrice = ((RLPItem) transaction.get(1)).getRLPData();
this.gasLimit = ((RLPItem) transaction.get(2)).getRLPData();
this.receiveAddress = ((RLPItem) transaction.get(3)).getRLPData();
this.value = ((RLPItem) transaction.get(4)).getRLPData();
this.data = ((RLPItem) transaction.get(5)).getRLPData();
/* Order of the Yellow Paper / eth-go & pyethereum clients
this.nonce = ((RLPItem) transaction.get(0)).getRLPData();
this.value = ((RLPItem) transaction.get(1)).getRLPData();
this.receiveAddress = ((RLPItem) transaction.get(2)).getRLPData();
this.gasPrice = ((RLPItem) transaction.get(3)).getRLPData();
this.gasLimit = ((RLPItem) transaction.get(4)).getRLPData();
this.data = ((RLPItem) transaction.get(5)).getRLPData();
*/
if (params.size() == 9){ // Simple transaction
byte v = ((RLPItem) params.get(6)).getData()[0];
byte[] r = ((RLPItem) params.get(7)).getData();
byte[] s = ((RLPItem) params.get(8)).getData();
if (transaction.size() == 9){ // Simple transaction
byte v = ((RLPItem) transaction.get(6)).getRLPData()[0];
byte[] r = ((RLPItem) transaction.get(7)).getRLPData();
byte[] s = ((RLPItem) transaction.get(8)).getRLPData();
this.signature = ECDSASignature.fromComponents(r, s, v);
} else if (params.size() == 10){ // Contract creation transaction
this.init = ((RLPItem) params.get(6)).getData();
byte v = ((RLPItem) params.get(7)).getData()[0];
byte[] r = ((RLPItem) params.get(8)).getData();
byte[] s = ((RLPItem) params.get(9)).getData();
} else if (transaction.size() == 10){ // Contract creation transaction
this.init = ((RLPItem) transaction.get(6)).getRLPData();
byte v = ((RLPItem) transaction.get(7)).getRLPData()[0];
byte[] r = ((RLPItem) transaction.get(8)).getRLPData();
byte[] s = ((RLPItem) transaction.get(9)).getRLPData();
this.signature = ECDSASignature.fromComponents(r, s, v);
} else throw new RuntimeException("Wrong tx data element list size");
this.parsed = true;
}
public RLPList getRawData() {
return rawData;
}
public boolean isParsed() {
return parsed;
}
public byte[] getHash() {
if (!parsed) rlpParse();
return hash;
return HashUtil.sha3(this.getEncoded(false));
}
public byte[] getNonce() {
@ -194,4 +211,47 @@ public class Transaction {
", signatureS=" + Utils.toHexString(signature.s.toByteArray()) +
']';
}
public byte[] getEncoded(boolean signed) {
if(rlpEncoded == null) {
// TODO: Alternative clean way to encode, using RLP.encode() after it's optimized
// return new Object[] { nonce, value, receiveAddress, gasPrice,
// gasLimit, data, init, signature };
/* Temporary order for an RLP encoded transaction in cpp client */
byte[] nonce = RLP.encodeElement(this.nonce);
byte[] gasPrice = RLP.encodeElement(this.gasPrice);
byte[] gasLimit = RLP.encodeElement(this.gasLimit);
byte[] receiveAddress = RLP.encodeElement(this.receiveAddress);
byte[] value = RLP.encodeElement(this.value);
byte[] data = RLP.encodeElement(this.data);
if(signed) {
// byte[] signature = RLP.encodeElement(this.signature);
}
if(Arrays.equals(this.receiveAddress, new byte[0])) {
byte[] init = RLP.encodeElement(this.init);
this.rlpEncoded = RLP.encodeList(nonce, value, receiveAddress,
gasPrice, gasLimit, data, init);
} else {
this.rlpEncoded = RLP.encodeList(nonce, value, receiveAddress,
gasPrice, gasLimit, data);
}
/* Order of the Yellow Paper / eth-go & pyethereum clients
byte[] nonce = RLP.encodeElement(this.nonce);
byte[] value = RLP.encodeElement(this.value);
byte[] receiveAddress = RLP.encodeElement(this.receiveAddress);
byte[] gasPrice = RLP.encodeElement(this.gasPrice);
byte[] gasLimit = RLP.encodeElement(this.gasLimit);
byte[] data = RLP.encodeElement(this.data);
byte[] init = RLP.encodeElement(this.init);
*/
}
return rlpEncoded;
}
}

View File

@ -356,7 +356,7 @@ public class ECKey implements Serializable {
* Signs the given hash and returns the R and S components as BigIntegers
* and put them in ECDSASignature
*
* @param data to sign
* @param rlpData to sign
* @return ECDSASignature signature that contains the R and S components
*/
public ECDSASignature doSign(byte[] input) {

View File

@ -76,7 +76,7 @@ public class MainData {
if (blockChainDB.isEmpty())
return StaticMessages.GENESSIS_HASH;
else
return blockChainDB.get(blockChainDB.size() - 1).hash();
return blockChainDB.get(blockChainDB.size() - 1).getHash();
}

View File

@ -28,13 +28,13 @@ public class BlocksMessage extends Message {
RLPList paramsList = (RLPList) rawData.get(0);
if (Command.fromInt(((RLPItem) (paramsList).get(0)).getData()[0]) != BLOCKS) {
if (Command.fromInt(((RLPItem) (paramsList).get(0)).getRLPData()[0]) != BLOCKS) {
throw new Error("BlocksMessage: parsing for mal data");
}
for (int i = 1; i < paramsList.size(); ++i) {
RLPList rlpData = ((RLPList) paramsList.get(i));
Block blockData = new Block(rlpData);
Block blockData = new Block(rlpData.getRLPData());
this.blockDataList.add(blockData);
}
parsed = true;

View File

@ -25,11 +25,11 @@ public class DisconnectMessage extends Message {
RLPList paramsList = (RLPList) rawData.get(0);
if (Command.fromInt(((RLPItem)(paramsList).get(0)).getData()[0]) != DISCONNECT){
if (Command.fromInt(((RLPItem)(paramsList).get(0)).getRLPData()[0]) != DISCONNECT){
throw new Error("Disconnect: parsing for mal data");
}
byte[] reasonB = ((RLPItem)paramsList.get(1)).getData();
byte[] reasonB = ((RLPItem)paramsList.get(1)).getRLPData();
if (reasonB == null){
this.reason = DISCONNECT_REQUESTED;
} else {

View File

@ -49,17 +49,17 @@ public class GetChainMessage extends Message {
RLPList paramsList = (RLPList) rawData.get(0);
if (Command.fromInt(((RLPItem)(paramsList).get(0)).getData()[0]) != GET_CHAIN){
if (Command.fromInt(((RLPItem)(paramsList).get(0)).getRLPData()[0]) != GET_CHAIN){
throw new Error("GetChain: parsing for mal data");
}
int size = paramsList.size();
for (int i = 1; i < size - 1; ++i){
blockHashList.add(((RLPItem) paramsList.get(i)).getData());
blockHashList.add(((RLPItem) paramsList.get(i)).getRLPData());
}
// the last element is the num of requested blocks
byte[] blockNumB = ((RLPItem)paramsList.get(size - 1)).getData();
byte[] blockNumB = ((RLPItem)paramsList.get(size - 1)).getRLPData();
this.blockNum = new BigInteger(blockNumB);
this.parsed = true;

View File

@ -44,21 +44,21 @@ public class HelloMessage extends Message {
// the message does no distinguish between the 0 and null so here I check command code for null
// todo: find out if it can be 00
if (((RLPItem)(paramsList).get(0)).getData() != null){
if (((RLPItem)(paramsList).get(0)).getRLPData() != null){
throw new Error("HelloMessage: parsing for mal data");
}
this.protocolVersion = ((RLPItem) paramsList.get(1)).getData()[0];
this.protocolVersion = ((RLPItem) paramsList.get(1)).getRLPData()[0];
byte[] networkIdBytes = ((RLPItem) paramsList.get(2)).getData();
byte[] networkIdBytes = ((RLPItem) paramsList.get(2)).getRLPData();
this.networkId = networkIdBytes == null ? 0 : networkIdBytes[0] ;
this.clientId = new String(((RLPItem) paramsList.get(3)).getData());
this.capabilities = ((RLPItem) paramsList.get(4)).getData()[0];
this.clientId = new String(((RLPItem) paramsList.get(3)).getRLPData());
this.capabilities = ((RLPItem) paramsList.get(4)).getRLPData()[0];
ByteBuffer bb = ByteBuffer.wrap(((RLPItem) paramsList.get(5)).getData());
ByteBuffer bb = ByteBuffer.wrap(((RLPItem) paramsList.get(5)).getRLPData());
this.peerPort = bb.getShort();
this.peerId = ((RLPItem) paramsList.get(6)).getData();
this.peerId = ((RLPItem) paramsList.get(6)).getRLPData();
this.parsed = true;
// todo: what to do when mal data ?
}

View File

@ -25,10 +25,10 @@ public class NotInChainMessage extends Message {
public void parseRLP() {
RLPList paramsList = (RLPList) rawData.get(0);
if (Command.fromInt(((RLPItem)(paramsList).get(0)).getData()[0] & 0xFF) != NOT_IN_CHAIN){
if (Command.fromInt(((RLPItem)(paramsList).get(0)).getRLPData()[0] & 0xFF) != NOT_IN_CHAIN){
throw new Error("NotInChain Message: parsing for mal data");
}
hash = ((RLPItem)paramsList.get(1)).getData();
hash = ((RLPItem)paramsList.get(1)).getRLPData();
}
@Override

View File

@ -33,15 +33,15 @@ public class PeersMessage extends Message {
RLPList paramsList = (RLPList) rawData.get(0);
if (Command.fromInt(((RLPItem)(paramsList).get(0)).getData()[0] & 0xFF) != PEERS){
if (Command.fromInt(((RLPItem)(paramsList).get(0)).getRLPData()[0] & 0xFF) != PEERS){
throw new Error("PeersMessage: parsing for mal data");
}
for (int i = 1; i < paramsList.size(); ++i){
RLPList peerParams = (RLPList)paramsList.get(i);
byte[] ip = ((RLPItem) peerParams.get(0)).getData();
byte[] shortData = ((RLPItem) peerParams.get(1)).getData();
byte[] ip = ((RLPItem) peerParams.get(0)).getRLPData();
byte[] shortData = ((RLPItem) peerParams.get(1)).getRLPData();
short peerPort = 0;
if (shortData.length == 1)
peerPort = shortData[0];
@ -49,7 +49,7 @@ public class PeersMessage extends Message {
ByteBuffer bb = ByteBuffer.wrap(shortData, 0, shortData.length);
peerPort = bb.getShort();
}
byte[] peerId = ((RLPItem) peerParams.get(2)).getData();
byte[] peerId = ((RLPItem) peerParams.get(2)).getRLPData();
PeerData peer = new PeerData(ip, peerPort, peerId);
peers.add(peer);
}

View File

@ -30,7 +30,7 @@ public class TransactionsMessage extends Message {
public void parseRLP() {
RLPList paramsList = (RLPList) rawData.get(0);
if (Command.fromInt(((RLPItem)(paramsList).get(0)).getData()[0] & 0xFF) != TRANSACTIONS) {
if (Command.fromInt(((RLPItem)(paramsList).get(0)).getRLPData()[0] & 0xFF) != TRANSACTIONS) {
throw new Error("TransactionMessage: parsing for mal data");
}
@ -38,7 +38,7 @@ public class TransactionsMessage extends Message {
int size = paramsList.size();
for (int i = 1; i < size; ++i){
RLPList rlpTxData = (RLPList) paramsList.get(i);
Transaction tx = new Transaction(rlpTxData);
Transaction tx = new Transaction(rlpTxData.getRLPData());
transactions.add(tx);
}
parsed = true;

View File

@ -789,7 +789,9 @@ public class RLP {
public static byte[] encodeElement(byte[] srcData) {
if (srcData.length <= 0x37) {
if (srcData == null){
return new byte[] { 0x00 };
} else if (srcData.length <= 0x37) {
// length = 8X
byte length = (byte) (OFFSET_SHORT_ITEM + srcData.length);
byte[] data = Arrays.copyOf(srcData, srcData.length + 1);

View File

@ -1,8 +1,11 @@
package org.ethereum.util;
import java.io.Serializable;
/**
* Wrapper class for decoded elements from an RLP encoded byte array.
*/
public interface RLPElement {
public interface RLPElement extends Serializable {
public byte[] getRLPData();
}

View File

@ -1,24 +1,22 @@
package org.ethereum.util;
import java.io.Serializable;
/**
* www.ethereumJ.com
* User: Roman Mandeleil
* Created on: 21/04/14 16:26
*/
public class RLPItem implements RLPElement, Serializable {
public class RLPItem implements RLPElement {
byte[] data;
public RLPItem(byte[] data) {
this.data = data;
byte[] rlpData;
public RLPItem(byte[] rlpData) {
this.rlpData = rlpData;
}
public byte[] getData() {
if (data.length == 0)
public byte[] getRLPData() {
if (rlpData.length == 0)
return null;
return data;
return rlpData;
}
}

View File

@ -11,7 +11,7 @@ public class RLPList extends ArrayList<RLPElement> implements RLPElement {
byte[] rlpData;
public void setRLPData(byte[] rlpData){
public void setRLPData(byte[] rlpData) {
this.rlpData = rlpData;
}
@ -32,7 +32,7 @@ public class RLPList extends ArrayList<RLPElement> implements RLPElement {
}
System.out.print("]");
} else {
String hex = Utils.toHexString(((RLPItem) element).getData());
String hex = Utils.toHexString(((RLPItem) element).getRLPData());
System.out.print(hex + ", ");
}
}

View File

@ -1,19 +1,16 @@
package org.ethereum.block;
package org.ethereum.core;
import org.spongycastle.util.encoders.Hex;
import org.ethereum.core.Block;
import org.ethereum.core.Genesis;
import org.ethereum.crypto.HashUtil;
import org.ethereum.util.ByteUtil;
import org.ethereum.util.RLP;
import org.ethereum.util.RLPList;
import org.junit.Test;
import static org.junit.Assert.*;
import java.io.IOException;
import java.math.BigInteger;
import java.nio.ByteBuffer;
public class BlockTest {
@ -123,7 +120,7 @@ public class BlockTest {
public void testGenesisFromRLP(){
// from RLP encoding
byte[] genesisBytes = Hex.decode(CPP_PoC5_GENESIS_HEX_RLP_ENCODED);
Block genesis = new Block(RLP.decode2(genesisBytes));
Block genesis = new Block(genesisBytes);
assertEquals(CPP_PoC5_GENESIS_HEX_HASH, Hex.toHexString(genesis.getHash()));
}
@ -158,11 +155,8 @@ public class BlockTest {
String blocksMsg = "F8C8F8C4A07B2536237CBF114A043B0F9B27C76F84AC160EA5B87B53E42C7E76148964D450A01DCC4DE8DEC75D7AAB85B567B6CCD41AD312451B948A7413F0A142FD40D49347943854AAF203BA5F8D49B1EC221329C7AEBCF050D3A07A3BE0EE10ECE4B03097BF74AABAC628AA0FAE617377D30AB1B97376EE31F41AA01DCC4DE8DEC75D7AAB85B567B6CCD41AD312451B948A7413F0A142FD40D49347833FBFE884533F1CE880A0000000000000000000000000000000000000000000000000F3DEEA84969B6E95C0C0";
byte[] payload = Hex.decode(blocksMsg);
RLPList rlpList = RLP.decode2(payload);
Block blockData = new Block(rlpList);
RLPList.recursivePrint(rlpList);
Block blockData = new Block(payload);
System.out.println(blockData.toString());
}
@Test /* create BlockData from part of real RLP BLOCKS message POC-5 */
@ -171,15 +165,9 @@ public class BlockTest {
String blocksMsg = "F8D1A0085F6A51A63D1FBA43D6E5FE166A47BED64A8B93A99012537D50F3279D4CEA52A01DCC4DE8DEC75D7AAB85B567B6CCD41AD312451B948A7413F0A142FD40D4934794D8758B101609A9F2A881A017BA86CBE6B7F0581DA068472689EA736CFC6B18FCAE9BA7454BADF9C65333A0317DFEFAE1D4AFFF6F90A000000000000000000000000000000000000000000000000000000000000000008401EDF1A18222778609184E72A0008080845373B0B180A0000000000000000000000000000000000000000000000000D1C0D8BC6D744943C0C0";
byte[] payload = Hex.decode(blocksMsg);
RLPList rlpList = RLP.decode2(payload);
Block blockData = new Block(rlpList);
Block blockData = new Block(payload);
System.out.println(blockData.toString());
RLPList.recursivePrint(rlpList);
}
}
/*

View File

@ -0,0 +1,69 @@
package org.ethereum.core;
import static org.junit.Assert.*;
import java.math.BigInteger;
import org.junit.Test;
import org.spongycastle.util.encoders.Hex;
public class TransactionTest {
private static String RLP_ENCODED_TX = "f88b8085e8d4a510008227109413978aee95f38490e9769c39b2773ed763d9cd5f872386f26fc10000a0c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a4701ca00502e84be138ca397e49f96e8c82e5a99afc09e0ea4582cc109ea221eeb479efa078f18d645b39ec44778c12ffc4b0";
private static String RLP_ENCODED_TX2 = "f8ccf8a6808609184e72a0008227109491a10664d0cd489085a7a018beb5245d4f2272f180b840000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011ca0c2604bd6eeca76afce4e7775d87960e3d4ed3b69235a3f94d6f1497c9831b50ca0664124a6b323350dd57a650434dc6bf8ddf37cd1a2686fee377e512aa12f1214a0c84f20b2df6abd635babd7af64cd76756cd4e39c0ccb87eaaaad609f21d1fe51820334";
private static String HASH_RAW_TX = "";
private static String HASH_SIGNED_TX = "";
@Test
public void testTransactionFromRLP() {
// from RLP encoding
byte[] encodedTxBytes = Hex.decode(RLP_ENCODED_TX2);
Transaction tx = new Transaction(encodedTxBytes);
assertNull(Hex.toHexString(tx.getNonce()));
assertNull(Hex.toHexString(tx.getValue()));
assertEquals(RLP_ENCODED_TX2, Hex.toHexString(tx.getReceiveAddress()));
assertEquals(RLP_ENCODED_TX2, Hex.toHexString(tx.getGasPrice()));
assertEquals(RLP_ENCODED_TX2, Hex.toHexString(tx.getGasLimit()));
assertEquals(RLP_ENCODED_TX2, Hex.toHexString(tx.getData()));
assertEquals(RLP_ENCODED_TX2, Hex.toHexString(tx.getInit()));
assertEquals(28, tx.getSignature().v);
assertEquals("c2604bd6eeca76afce4e7775d87960e3d4ed3b69235a3f94d6f1497c9831b50c", tx.getSignature().r);
assertEquals("664124a6b323350dd57a650434dc6bf8ddf37cd1a2686fee377e512aa12f1214", tx.getSignature().s);
assertEquals(RLP_ENCODED_TX2, Hex.toHexString(tx.getEncoded(false)));
}
@Test
public void testTransactionFromNew() throws Exception {
byte[] privKeyBytes = Hex.decode("3ecb44df2159c26e0f995712d4f39b6f6e499b40749b1cf1246c37f9516cb6a4");
// nonce=0, gasprice=10 ** 12, startgas=10000, to=, value=10 ** 16, data='').sign(k)
// byte[] nonce = BigInteger.ZERO.toByteArray();
// byte[] value = Denomination.ETHER.getDenomination().toByteArray();
// byte[] recieveAddress = Hex.decode("8a40bfaa73256b60764c1bf40675a99083efb075");
// byte[] gasPrice = Denomination.SZABO.getDenomination().toByteArray();
// byte[] gas = new BigInteger("10000").toByteArray();
// byte[] data = new byte[0];
byte[] nonce = null;
byte[] value = null;
byte[] recieveAddress = Hex.decode("91a10664d0cd489085a7a018beb5245d4f2272f1");
byte[] gasPrice = Hex.decode("09184e72a000");
byte[] gas = Hex.decode("2710");
byte[] data = Hex.decode("00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001");
Transaction tx = new Transaction(nonce, value, recieveAddress, gasPrice, gas, data);
byte[] encoded = tx.getEncoded(false);
String test = Hex.toHexString(encoded);
System.out.println(RLP_ENCODED_TX2);
System.out.println(test);
assertEquals(RLP_ENCODED_TX2, test);
assertEquals(HASH_RAW_TX, Hex.toHexString(tx.getHash()));
tx.sign(privKeyBytes);
assertEquals(HASH_RAW_TX, Hex.toHexString(tx.getHash()));
}
}

View File

@ -1,8 +1,6 @@
package org.ethereum.util;
import org.spongycastle.util.encoders.Hex;
import org.ethereum.core.Block;
import org.ethereum.core.Genesis;
import org.ethereum.crypto.HashUtil;
import org.ethereum.util.Utils;
import org.junit.Test;
@ -234,6 +232,13 @@ public class RLPTest {
byte[] actuals = RLP.encodeList();
assertArrayEquals(new byte[] { (byte) 0xc0 }, actuals);
}
@Test /** encode list */
public void testEncodeElementNull(){
byte[] actuals = RLP.encodeElement(null);
assertArrayEquals(new byte[] { (byte) 0x00 }, actuals);
}
@Test /** found bug encode list affects element value,
hhh... not really at the end but keep the test */