mirror of
https://github.com/status-im/ethereumj-personal.git
synced 2025-01-24 10:49:43 +00:00
Change block and uncle reward with extra validation for poc6
This commit is contained in:
parent
d45db5ada3
commit
f1c5a42dce
@ -1,17 +1,13 @@
|
||||
package org.ethereum.core;
|
||||
|
||||
import org.ethereum.crypto.HashUtil;
|
||||
import org.ethereum.manager.WorldManager;
|
||||
import org.ethereum.trie.Trie;
|
||||
import org.ethereum.util.ByteUtil;
|
||||
import org.ethereum.util.FastByteComparisons;
|
||||
import org.ethereum.util.RLP;
|
||||
import org.ethereum.util.RLPElement;
|
||||
import org.ethereum.util.RLPList;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.spongycastle.util.Arrays;
|
||||
import org.spongycastle.util.BigIntegers;
|
||||
import org.spongycastle.util.encoders.Hex;
|
||||
|
||||
import java.math.BigInteger;
|
||||
@ -34,11 +30,11 @@ public class Block {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger("block");
|
||||
|
||||
/* A scalar value equal to the mininum limit of gas expenditure per block */
|
||||
private static long MIN_GAS_LIMIT = 125000L;
|
||||
public static BigInteger BLOCK_REWARD = BigInteger.valueOf(1500000000000000000L);
|
||||
public static BigInteger UNCLE_REWARD = BLOCK_REWARD.multiply(
|
||||
BigInteger.valueOf(3)).divide(BigInteger.valueOf(4));
|
||||
BigInteger.valueOf(15)).divide(BigInteger.valueOf(16));
|
||||
public static BigInteger INCLUSION_REWARD = Block.BLOCK_REWARD
|
||||
.divide(BigInteger.valueOf(32));
|
||||
|
||||
private BlockHeader header;
|
||||
|
||||
@ -111,12 +107,28 @@ public class Block {
|
||||
|
||||
public byte[] getHash() {
|
||||
if (!parsed) parseRLP();
|
||||
return HashUtil.sha3(this.getEncoded());
|
||||
return HashUtil.sha3(this.header.getEncoded());
|
||||
}
|
||||
|
||||
public Block getParent() {
|
||||
return WorldManager.getInstance().getBlockchain().getBlockByNumber(this.getNumber() - 1);
|
||||
}
|
||||
return this.header.getParent();
|
||||
}
|
||||
|
||||
public byte[] calcDifficulty() {
|
||||
if (!parsed) parseRLP();
|
||||
return this.header.calcDifficulty();
|
||||
}
|
||||
|
||||
public long calcGasLimit() {
|
||||
if (!parsed) parseRLP();
|
||||
return this.header.calcGasLimit();
|
||||
}
|
||||
|
||||
public boolean validateNonce() {
|
||||
if (!parsed) parseRLP();
|
||||
return this.header.validateNonce();
|
||||
}
|
||||
|
||||
|
||||
public byte[] getParentHash() {
|
||||
if (!parsed) parseRLP();
|
||||
@ -167,10 +179,6 @@ public class Block {
|
||||
if (!parsed) parseRLP();
|
||||
return this.header.getMinGasPrice();
|
||||
}
|
||||
|
||||
public boolean isGenesis() {
|
||||
return this.getNumber() == Genesis.NUMBER;
|
||||
}
|
||||
|
||||
public long getGasLimit() {
|
||||
if (!parsed) parseRLP();
|
||||
@ -323,72 +331,37 @@ public class Block {
|
||||
* and expected time to the next block, is reduced.
|
||||
*/
|
||||
public boolean isValid() {
|
||||
boolean isValid = true;
|
||||
boolean isValid = false;
|
||||
|
||||
if(!this.isGenesis()) {
|
||||
// verify difficulty meets requirements
|
||||
isValid = this.getDifficulty() == this.calcDifficulty();
|
||||
isValid = this.validateNonce();
|
||||
// verify gasLimit meets requirements
|
||||
isValid = this.getGasLimit() == this.calcGasLimit();
|
||||
// verify timestamp meets requirements
|
||||
isValid = this.getTimestamp() > this.getParent().getTimestamp();
|
||||
// verify extraData doesn't exceed 1024 bytes
|
||||
isValid = this.getExtraData() == null || this.getExtraData().length <= 1024;
|
||||
isValid = this.header.isValid();
|
||||
|
||||
for (BlockHeader uncle : uncleList) {
|
||||
// - They are valid headers (not necessarily valid blocks)
|
||||
isValid = uncle.isValid();
|
||||
// - Their parent is a kth generation ancestor for k in {2, 3, 4, 5, 6, 7}
|
||||
long generationGap = this.getNumber() - uncle.getParent().getNumber();
|
||||
isValid = generationGap > 1 && generationGap < 8;
|
||||
// - They were not uncles of the kth generation ancestor for k in {1, 2, 3, 4, 5, 6}
|
||||
generationGap = this.getNumber() - uncle.getNumber();
|
||||
isValid = generationGap > 0 && generationGap < 7;
|
||||
}
|
||||
}
|
||||
if(!isValid)
|
||||
logger.warn("!!!Invalid block!!!");
|
||||
return isValid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate GasLimit
|
||||
* See Yellow Paper: http://www.gavwood.com/Paper.pdf - page 5, 4.3.4 (25)
|
||||
* @return long value of the gasLimit
|
||||
*/
|
||||
public long calcGasLimit() {
|
||||
if (this.isGenesis())
|
||||
return Genesis.GAS_LIMIT;
|
||||
else {
|
||||
Block parent = this.getParent();
|
||||
return Math.max(MIN_GAS_LIMIT, (parent.getGasLimit() * (1024 - 1) + (parent.getGasUsed() * 6 / 5)) / 1024);
|
||||
}
|
||||
|
||||
public boolean isGenesis() {
|
||||
return this.header.isGenesis();
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate Difficulty
|
||||
* See Yellow Paper: http://www.gavwood.com/Paper.pdf - page 5, 4.3.4 (24)
|
||||
* @return byte array value of the difficulty
|
||||
*/
|
||||
public byte[] calcDifficulty() {
|
||||
if (this.isGenesis())
|
||||
return Genesis.DIFFICULTY;
|
||||
else {
|
||||
Block parent = this.getParent();
|
||||
long parentDifficulty = new BigInteger(1, parent.getDifficulty()).longValue();
|
||||
long newDifficulty = this.header.getTimestamp() < parent.getTimestamp() + 5 ? parentDifficulty - (parentDifficulty >> 10) : (parentDifficulty + (parentDifficulty >> 10));
|
||||
return BigIntegers.asUnsignedByteArray(BigInteger.valueOf(newDifficulty));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that block is valid for its difficulty
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public boolean validateNonce() {
|
||||
BigInteger max = BigInteger.valueOf(2).pow(256);
|
||||
byte[] target = BigIntegers.asUnsignedByteArray(32,
|
||||
max.divide(new BigInteger(1, this.getDifficulty())));
|
||||
byte[] hash = HashUtil.sha3(this.getEncodedWithoutNonce());
|
||||
byte[] concat = Arrays.concatenate(hash, this.getNonce());
|
||||
byte[] result = HashUtil.sha3(concat);
|
||||
return FastByteComparisons.compareTo(result, 0, 32, target, 0, 32) < 0;
|
||||
}
|
||||
|
||||
public byte[] getEncoded() {
|
||||
if(rlpEncoded == null) {
|
||||
this.rlpEncoded = this.header.getEncoded();
|
||||
byte[] header = this.header.getEncoded();
|
||||
byte[] transactions = RLP.encodeList();
|
||||
byte[] uncles = RLP.encodeList();
|
||||
this.rlpEncoded = RLP.encodeList(header, transactions, uncles);
|
||||
}
|
||||
return rlpEncoded;
|
||||
}
|
||||
@ -397,7 +370,7 @@ public class Block {
|
||||
if (!parsed) parseRLP();
|
||||
byte[] header = this.header.getEncodedWithoutNonce();
|
||||
byte[] transactions = RLP.encodeList();
|
||||
byte[] uncles = RLP.encodeList();
|
||||
byte[] uncles = RLP.encodeList();
|
||||
|
||||
return RLP.encodeList(header, transactions, uncles);
|
||||
}
|
||||
|
@ -3,10 +3,16 @@ package org.ethereum.core;
|
||||
import java.math.BigInteger;
|
||||
|
||||
import static org.ethereum.util.ByteUtil.*;
|
||||
|
||||
import org.ethereum.crypto.HashUtil;
|
||||
import org.ethereum.manager.WorldManager;
|
||||
import org.ethereum.util.FastByteComparisons;
|
||||
import org.ethereum.util.RLP;
|
||||
import org.ethereum.util.RLPItem;
|
||||
import org.ethereum.util.RLPList;
|
||||
import org.ethereum.util.Utils;
|
||||
import org.spongycastle.util.Arrays;
|
||||
import org.spongycastle.util.BigIntegers;
|
||||
|
||||
/**
|
||||
* Block header is a value object containing
|
||||
@ -14,6 +20,9 @@ import org.ethereum.util.Utils;
|
||||
*/
|
||||
public class BlockHeader {
|
||||
|
||||
/* A scalar value equal to the mininum limit of gas expenditure per block */
|
||||
private static long MIN_GAS_LIMIT = 125000L;
|
||||
|
||||
/* The SHA3 256-bit hash of the parent block, in its entirety */
|
||||
private byte[] parentHash;
|
||||
/* The SHA3 256-bit hash of the uncles list portion of this block */
|
||||
@ -97,7 +106,74 @@ public class BlockHeader {
|
||||
this.extraData = extraData;
|
||||
this.nonce = nonce;
|
||||
}
|
||||
|
||||
public boolean isValid() {
|
||||
boolean isValid = false;
|
||||
// verify difficulty meets requirements
|
||||
isValid = this.getDifficulty() == this.calcDifficulty();
|
||||
isValid = this.validateNonce();
|
||||
// verify gasLimit meets requirements
|
||||
isValid = this.getGasLimit() == this.calcGasLimit();
|
||||
// verify timestamp meets requirements
|
||||
isValid = this.getTimestamp() > this.getParent().getTimestamp();
|
||||
// verify extraData doesn't exceed 1024 bytes
|
||||
isValid = this.getExtraData() == null || this.getExtraData().length <= 1024;
|
||||
return isValid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate Difficulty
|
||||
* See Yellow Paper: http://www.gavwood.com/Paper.pdf - page 5, 4.3.4 (24)
|
||||
* @return byte array value of the difficulty
|
||||
*/
|
||||
public byte[] calcDifficulty() {
|
||||
if (this.isGenesis())
|
||||
return Genesis.DIFFICULTY;
|
||||
else {
|
||||
Block parent = this.getParent();
|
||||
long parentDifficulty = new BigInteger(1, parent.getDifficulty()).longValue();
|
||||
long newDifficulty = this.getTimestamp() < parent.getTimestamp() + 5 ? parentDifficulty - (parentDifficulty >> 10) : (parentDifficulty + (parentDifficulty >> 10));
|
||||
return BigIntegers.asUnsignedByteArray(BigInteger.valueOf(newDifficulty));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate GasLimit
|
||||
* See Yellow Paper: http://www.gavwood.com/Paper.pdf - page 5, 4.3.4 (25)
|
||||
* @return long value of the gasLimit
|
||||
*/
|
||||
public long calcGasLimit() {
|
||||
if (this.isGenesis())
|
||||
return Genesis.GAS_LIMIT;
|
||||
else {
|
||||
Block parent = this.getParent();
|
||||
return Math.max(MIN_GAS_LIMIT, (parent.getGasLimit() * (1024 - 1) + (parent.getGasUsed() * 6 / 5)) / 1024);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that block is valid for its difficulty
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public boolean validateNonce() {
|
||||
BigInteger max = BigInteger.valueOf(2).pow(256);
|
||||
byte[] target = BigIntegers.asUnsignedByteArray(32,
|
||||
max.divide(new BigInteger(1, this.getDifficulty())));
|
||||
byte[] hash = HashUtil.sha3(this.getEncodedWithoutNonce());
|
||||
byte[] concat = Arrays.concatenate(hash, this.getNonce());
|
||||
byte[] result = HashUtil.sha3(concat);
|
||||
return FastByteComparisons.compareTo(result, 0, 32, target, 0, 32) < 0;
|
||||
}
|
||||
|
||||
public boolean isGenesis() {
|
||||
return this.getNumber() == Genesis.NUMBER;
|
||||
}
|
||||
|
||||
public Block getParent() {
|
||||
return WorldManager.getInstance().getBlockchain().getBlockByNumber(this.getNumber() - 1);
|
||||
}
|
||||
|
||||
public byte[] getParentHash() {
|
||||
return parentHash;
|
||||
}
|
||||
|
@ -168,8 +168,10 @@ public class BlockchainImpl implements Blockchain {
|
||||
}
|
||||
|
||||
/**
|
||||
* Add reward to block- and every uncle coinbase
|
||||
* assuming the entire block is valid.
|
||||
*
|
||||
* @param block
|
||||
* @param block object containing the header and uncles
|
||||
*/
|
||||
private void addReward(Block block) {
|
||||
// Create coinbase if doesn't exist yet
|
||||
@ -177,19 +179,17 @@ public class BlockchainImpl implements Blockchain {
|
||||
repository.createAccount(block.getCoinbase());
|
||||
|
||||
// Add standard block reward
|
||||
repository.addBalance(block.getCoinbase(), Block.BLOCK_REWARD);
|
||||
BigInteger totalBlockReward = Block.BLOCK_REWARD;
|
||||
|
||||
// Add extra rewards based on number of uncles
|
||||
if(block.getUncleList().size() > 0) {
|
||||
BigInteger partialReward = Block.BLOCK_REWARD
|
||||
.multiply(BigInteger.valueOf(1 * block.getUncleList().size()))
|
||||
.divide(BigInteger.valueOf(8));
|
||||
repository.addBalance(block.getCoinbase(), partialReward);
|
||||
|
||||
for (BlockHeader uncle : block.getUncleList()) {
|
||||
repository.addBalance(uncle.getCoinbase(), Block.UNCLE_REWARD);
|
||||
}
|
||||
totalBlockReward.add(Block.INCLUSION_REWARD
|
||||
.multiply(BigInteger.valueOf(block.getUncleList().size())));
|
||||
}
|
||||
repository.addBalance(block.getCoinbase(), totalBlockReward);
|
||||
}
|
||||
|
||||
public void storeBlock(Block block) {
|
||||
|
@ -5,6 +5,7 @@ import java.math.BigInteger;
|
||||
import org.ethereum.manager.WorldManager;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Ignore;
|
||||
import org.spongycastle.util.encoders.Hex;
|
||||
import org.junit.Test;
|
||||
|
||||
@ -24,15 +25,9 @@ public class BlockTest {
|
||||
}
|
||||
|
||||
// https://ethereum.etherpad.mozilla.org/12
|
||||
private String CPP_PoC5_GENESIS_HEX_RLP_ENCODED = "f8abf8a7a00000000000000000000000000000000000000000000000000000000000000000a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347940000000000000000000000000000000000000000a08dbd704eb38d1c2b73ee4788715ea5828a030650829703f077729b2b613dd20680834000008080830f4240808080a004994f67dc55b09e814ab7ffc8df3686b4afb2bb53e60eae97ef043fe03fb829c0c0";
|
||||
private String CPP_PoC5_GENESIS_HEX_HASH = "a7722d611450de26f55026b6544e34d9431b0a67a829e1794ac36fa4f079208f";
|
||||
private String PoC6_GENESIS_HEX_RLP_ENCODED = "f8abf8a7a00000000000000000000000000000000000000000000000000000000000000000a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347940000000000000000000000000000000000000000a008bf6a98374f333b84e7d063d607696ac7cbbd409bd20fbe6a741c2dfc0eb28580830200008080830f4240808080a004994f67dc55b09e814ab7ffc8df3686b4afb2bb53e60eae97ef043fe03fb829c0c0";
|
||||
private String PoC6_GENESIS_HEX_HASH = "08436a4d33c77e6acf013e586a3333ad152f25d31df8b68749d85046810e1f4b";
|
||||
|
||||
String block_1 = "f8abf8a7a0000000000000000000000000000000000000000000000000000000"
|
||||
+ "0000000000a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d"
|
||||
+ "49347940000000000000000000000000000000000000000a08dbd704eb38d1c2b73ee47"
|
||||
+ "88715ea5828a030650829703f077729b2b613dd20680834000008080830f4240808080a"
|
||||
+ "004994f67dc55b09e814ab7ffc8df3686b4afb2bb53e60eae97ef043fe03fb829c0c0";
|
||||
|
||||
String block_2 = "f8b5f8b1a0cf4b25b08b39350304fe12a16e4216c01a426f8f3dbf0d392b5b45"
|
||||
+ "8ffb6a399da01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a1"
|
||||
+ "42fd40d493479476f5eabe4b342ee56b8ceba6ab2a770c3e2198e7a08a22d58b"
|
||||
@ -62,7 +57,7 @@ public class BlockTest {
|
||||
@Test /* got from go guy */
|
||||
public void testGenesisFromRLP() {
|
||||
// from RLP encoding
|
||||
byte[] genesisBytes = Hex.decode(CPP_PoC5_GENESIS_HEX_RLP_ENCODED);
|
||||
byte[] genesisBytes = Hex.decode(PoC6_GENESIS_HEX_RLP_ENCODED);
|
||||
Block genesisFromRLP = new Block(genesisBytes);
|
||||
Block genesis = Genesis.getInstance();
|
||||
assertEquals(Hex.toHexString(genesis.getHash()), Hex.toHexString(genesisFromRLP.getHash()));
|
||||
@ -91,8 +86,8 @@ public class BlockTest {
|
||||
)
|
||||
*/
|
||||
Block genesis = Genesis.getInstance();
|
||||
assertEquals(CPP_PoC5_GENESIS_HEX_RLP_ENCODED, Hex.toHexString(genesis.getEncoded()));
|
||||
assertEquals(CPP_PoC5_GENESIS_HEX_HASH, Hex.toHexString(genesis.getHash()));
|
||||
assertEquals(PoC6_GENESIS_HEX_HASH, Hex.toHexString(genesis.getHash()));
|
||||
assertEquals(PoC6_GENESIS_HEX_RLP_ENCODED, Hex.toHexString(genesis.getEncoded()));
|
||||
}
|
||||
|
||||
@Test /* block without transactions - block#32 in PoC5 cpp-chain */
|
||||
@ -111,7 +106,7 @@ public class BlockTest {
|
||||
|
||||
@Test /* large block with 5 transactions -block#1 in PoC5 cpp-chain */
|
||||
public void testBlockWithContractCreation() {
|
||||
byte[] payload = Hex.decode(block_1);
|
||||
byte[] payload = Hex.decode(PoC6_GENESIS_HEX_RLP_ENCODED);
|
||||
Block block = new Block(payload);
|
||||
System.out.println(block.toString());
|
||||
}
|
||||
@ -127,7 +122,7 @@ public class BlockTest {
|
||||
// Storing genesis because the parent needs to be in the DB for calculation.
|
||||
WorldManager.getInstance().getBlockchain().add(genesis);
|
||||
|
||||
Block block1 = new Block(Hex.decode(block_1));
|
||||
Block block1 = new Block(Hex.decode(PoC6_GENESIS_HEX_RLP_ENCODED));
|
||||
BigInteger calcDifficulty = new BigInteger(1, block1.calcDifficulty());
|
||||
BigInteger actualDifficulty = new BigInteger(1, block1.getDifficulty());
|
||||
System.out.println("Block#1 actual difficulty = " + actualDifficulty.toString());
|
||||
@ -147,11 +142,32 @@ public class BlockTest {
|
||||
WorldManager.getInstance().getBlockchain().add(genesis);
|
||||
|
||||
// Test with block
|
||||
Block block1 = new Block(Hex.decode(block_1));
|
||||
Block block1 = new Block(Hex.decode(PoC6_GENESIS_HEX_RLP_ENCODED));
|
||||
long calcGasLimit = block1.calcGasLimit();
|
||||
long actualGasLimit = block1.getGasLimit();
|
||||
System.out.println("Block#1 actual gasLimit = " + actualGasLimit);
|
||||
System.out.println("Block#1 calculated gasLimit = " + calcGasLimit);
|
||||
assertEquals(actualGasLimit, calcGasLimit);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Ignore
|
||||
public void testUncleValidGenerationGap() {
|
||||
// TODO
|
||||
fail("Not yet implemented");
|
||||
}
|
||||
|
||||
@Test
|
||||
@Ignore
|
||||
public void testUncleInvalidGenerationGap() {
|
||||
// TODO
|
||||
fail("Not yet implemented");
|
||||
}
|
||||
|
||||
@Test
|
||||
@Ignore
|
||||
public void testUncleInvalidParentGenerationGap() {
|
||||
// TODO
|
||||
fail("Not yet implemented");
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user