Skip to content

Commit

Permalink
Merge pull request #1182 from rsksmart/umm_upgrade
Browse files Browse the repository at this point in the history
UMM Upgrade
  • Loading branch information
aeidelman authored Mar 13, 2020
2 parents c9ab241 + 52fca5c commit 32dbe67
Show file tree
Hide file tree
Showing 17 changed files with 615 additions and 114 deletions.
4 changes: 4 additions & 0 deletions rskj-core/src/main/java/co/rsk/mine/BlockToMineBuilder.java
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,9 @@ private BlockHeader createHeader(

long blockNumber = newBlockParentHeader.getNumber() + 1;

// ummRoot can not be set to a value yet since the UMM contracts are not yet implemented
byte[] ummRoot = activationConfig.isActive(ConsensusRule.RSKIPUMM, blockNumber) ? new byte[0] : null;

final BlockHeader newHeader = blockFactory
.getBlockHeaderBuilder()
.setParentHash(newBlockParentHeader.getHash().getBytes())
Expand All @@ -214,6 +217,7 @@ private BlockHeader createHeader(
.setMergedMiningForkDetectionData(forkDetectionData)
.setMinimumGasPrice(minimumGasPrice)
.setUncleCount(uncles.size())
.setUmmRoot(ummRoot)
.build();

newHeader.setDifficulty(difficultyCalculator.calcDifficulty(newHeader, newBlockParentHeader));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,8 @@ public enum ConsensusRule {
RSKIP150("rskip150"),
RSKIP151("rskip151"),
RSKIP152("rskip152"),
RSKIP156("rskip156");
RSKIP156("rskip156"),
RSKIPUMM("rskipUMM");

private String configKey;

Expand Down
56 changes: 37 additions & 19 deletions rskj-core/src/main/java/org/ethereum/core/BlockFactory.java
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,8 @@
import static org.ethereum.crypto.HashUtil.EMPTY_TRIE_HASH;

public class BlockFactory {
private static final int RLP_HEADER_SIZE = 16;
private static final int RLP_HEADER_SIZE_WITH_MERGED_MINING = 19;
private static final int RLP_HEADER_SIZE = 17;
private static final int RLP_HEADER_SIZE_WITH_MERGED_MINING = 20;

private final ActivationConfig activationConfig;

Expand Down Expand Up @@ -97,14 +97,6 @@ public BlockHeader decodeHeader(byte[] encoded) {
}

private BlockHeader decodeHeader(RLPList rlpHeader, boolean sealed) {
// TODO fix old tests that have other sizes
if (rlpHeader.size() != RLP_HEADER_SIZE && rlpHeader.size() != RLP_HEADER_SIZE_WITH_MERGED_MINING) {
throw new IllegalArgumentException(String.format(
"A block header must have 16 elements or 19 including merged-mining fields but it had %d",
rlpHeader.size()
));
}

byte[] parentHash = rlpHeader.get(0).getRLPData();
byte[] unclesHash = rlpHeader.get(1).getRLPData();
byte[] coinBaseBytes = rlpHeader.get(2).getRLPData();
Expand Down Expand Up @@ -133,7 +125,7 @@ private BlockHeader decodeHeader(RLPList rlpHeader, boolean sealed) {
byte[] guBytes = rlpHeader.get(10).getRLPData();
byte[] tsBytes = rlpHeader.get(11).getRLPData();

long number = parseBigInteger(nrBytes).longValueExact();
long blockNumber = parseBigInteger(nrBytes).longValueExact();

long gasUsed = parseBigInteger(guBytes).longValueExact();
long timestamp = parseBigInteger(tsBytes).longValueExact();
Expand All @@ -144,14 +136,32 @@ private BlockHeader decodeHeader(RLPList rlpHeader, boolean sealed) {
byte[] minimumGasPriceBytes = rlpHeader.get(14).getRLPData();
Coin minimumGasPrice = RLP.parseSignedCoinNonNullZero(minimumGasPriceBytes);

if (!canBeDecoded(rlpHeader, blockNumber)) {
throw new IllegalArgumentException(String.format(
"A block header must have 16/17 elements or 19/20 including merged-mining fields but it had %d",
rlpHeader.size()
));
}

int r = 15;

boolean isUmm = activationConfig.isActive(ConsensusRule.RSKIPUMM, blockNumber);

boolean includeUncleCount = isUmm ||
// sizes prior to UMM activation
rlpHeader.size() == (RLP_HEADER_SIZE-1) || rlpHeader.size() == (RLP_HEADER_SIZE_WITH_MERGED_MINING-1);

int uncleCount = 0;
if (rlpHeader.size() == RLP_HEADER_SIZE || rlpHeader.size() == RLP_HEADER_SIZE_WITH_MERGED_MINING) {
if (includeUncleCount) {
byte[] ucBytes = rlpHeader.get(r++).getRLPData();
uncleCount = parseBigInteger(ucBytes).intValueExact();
}

byte[] ummRoot = null;
if (isUmm) {
ummRoot = rlpHeader.get(r++).getRLPRawData();
}

byte[] bitcoinMergedMiningHeader = null;
byte[] bitcoinMergedMiningMerkleProof = null;
byte[] bitcoinMergedMiningCoinbaseTransaction = null;
Expand All @@ -161,17 +171,17 @@ private BlockHeader decodeHeader(RLPList rlpHeader, boolean sealed) {
bitcoinMergedMiningCoinbaseTransaction = rlpHeader.get(r++).getRLPData();
}

boolean useRskip92Encoding = activationConfig.isActive(ConsensusRule.RSKIP92, number);
boolean includeForkDetectionData = activationConfig.isActive(ConsensusRule.RSKIP110, number) &&
number >= MiningConfig.REQUIRED_NUMBER_OF_BLOCKS_FOR_FORK_DETECTION_CALCULATION;
boolean useRskip92Encoding = activationConfig.isActive(ConsensusRule.RSKIP92, blockNumber);
boolean includeForkDetectionData = activationConfig.isActive(ConsensusRule.RSKIP110, blockNumber) &&
blockNumber >= MiningConfig.REQUIRED_NUMBER_OF_BLOCKS_FOR_FORK_DETECTION_CALCULATION;

if (number == Genesis.NUMBER) {
if (blockNumber == Genesis.NUMBER) {
return new GenesisHeader(
parentHash,
unclesHash,
logsBloom,
difficultyBytes,
number,
blockNumber,
glBytes,
gasUsed,
timestamp,
Expand All @@ -188,13 +198,21 @@ private BlockHeader decodeHeader(RLPList rlpHeader, boolean sealed) {
return new BlockHeader(
parentHash, unclesHash, coinbase, stateRoot,
txTrieRoot, receiptTrieRoot, logsBloom, difficulty,
number, glBytes, gasUsed, timestamp, extraData,
blockNumber, glBytes, gasUsed, timestamp, extraData,
paidFees, bitcoinMergedMiningHeader, bitcoinMergedMiningMerkleProof,
bitcoinMergedMiningCoinbaseTransaction, new byte[0],
minimumGasPrice, uncleCount, sealed, useRskip92Encoding, includeForkDetectionData
minimumGasPrice, uncleCount, sealed, useRskip92Encoding, includeForkDetectionData,
ummRoot
);
}

private boolean canBeDecoded(RLPList rlpHeader, long blockNumber) {
int preUmmHeaderSizeAdjustment = activationConfig.isActive(ConsensusRule.RSKIPUMM, blockNumber) ? 0 : 1;

return rlpHeader.size() == (RLP_HEADER_SIZE - preUmmHeaderSizeAdjustment) ||
rlpHeader.size() == (RLP_HEADER_SIZE_WITH_MERGED_MINING - preUmmHeaderSizeAdjustment);
}

private static BigInteger parseBigInteger(byte[] bytes) {
return bytes == null ? BigInteger.ZERO : BigIntegers.fromUnsignedByteArray(bytes);
}
Expand Down
38 changes: 37 additions & 1 deletion rskj-core/src/main/java/org/ethereum/core/BlockHeader.java
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ public class BlockHeader {

private static final int HASH_FOR_MERGED_MINING_PREFIX_LENGTH = 20;
private static final int FORK_DETECTION_DATA_LENGTH = 12;
private static final int UMM_LEAVES_LENGTH = 20;

/* The SHA3 256-bit hash of the parent block, in its entirety */
private byte[] parentHash;
Expand Down Expand Up @@ -102,6 +103,8 @@ public class BlockHeader {

private byte[] miningForkDetectionData;

private byte[] ummRoot;

/**
* The mgp for a tx to be included in the block.
*/
Expand All @@ -123,7 +126,7 @@ public BlockHeader(byte[] parentHash, byte[] unclesHash, RskAddress coinbase, by
Coin paidFees, byte[] bitcoinMergedMiningHeader, byte[] bitcoinMergedMiningMerkleProof,
byte[] bitcoinMergedMiningCoinbaseTransaction, byte[] mergedMiningForkDetectionData,
Coin minimumGasPrice, int uncleCount, boolean sealed,
boolean useRskip92Encoding, boolean includeForkDetectionData) {
boolean useRskip92Encoding, boolean includeForkDetectionData, byte[] ummRoot) {
this.parentHash = parentHash;
this.unclesHash = unclesHash;
this.coinbase = coinbase;
Expand All @@ -148,6 +151,7 @@ public BlockHeader(byte[] parentHash, byte[] unclesHash, RskAddress coinbase, by
this.sealed = sealed;
this.useRskip92Encoding = useRskip92Encoding;
this.includeForkDetectionData = includeForkDetectionData;
this.ummRoot = ummRoot != null ? Arrays.copyOf(ummRoot, ummRoot.length) : null;
}

@VisibleForTesting
Expand Down Expand Up @@ -349,6 +353,10 @@ public byte[] getEncoded(boolean withMergedMiningFields, boolean withMerkleProof
byte[] uncleCount = RLP.encodeBigInteger(BigInteger.valueOf(this.uncleCount));
fieldToEncodeList.add(uncleCount);

if (this.ummRoot != null) {
fieldToEncodeList.add(RLP.encodeElement(this.ummRoot));
}

if (withMergedMiningFields && hasMiningFields()) {
byte[] bitcoinMergedMiningHeader = RLP.encodeElement(this.bitcoinMergedMiningHeader);
fieldToEncodeList.add(bitcoinMergedMiningHeader);
Expand Down Expand Up @@ -477,9 +485,19 @@ public String getShortHashForMergedMining() {
return HashUtil.shortHash(getHashForMergedMining());
}

public boolean isUMMBlock() {
return this.ummRoot != null && this.ummRoot.length != 0;
}

public byte[] getHashForMergedMining() {
byte[] encodedBlock = getEncoded(false, false);
byte[] hashForMergedMining = HashUtil.keccak256(encodedBlock);

if (isUMMBlock()) {
byte[] leftHash = Arrays.copyOf(hashForMergedMining, UMM_LEAVES_LENGTH);
hashForMergedMining = this.getHashRootForMergedMining(leftHash);
}

if (includeForkDetectionData) {
byte[] mergedMiningForkDetectionData = hasMiningFields() ?
getMiningForkDetectionData() :
Expand All @@ -496,6 +514,20 @@ public byte[] getHashForMergedMining() {
return hashForMergedMining;
}

private byte[] getHashRootForMergedMining(byte[] leftHash) {
if (ummRoot.length != UMM_LEAVES_LENGTH){
throw new IllegalStateException(
String.format("UMM Root length must be either 0 or 20. Found: %d", ummRoot.length)
);
}

byte[] leftRight = Arrays.copyOf(leftHash, leftHash.length + ummRoot.length);
arraycopy(ummRoot, 0, leftRight, leftHash.length, ummRoot.length);

byte[] root256 = HashUtil.keccak256(leftRight);
return root256;
}

public String getShortHash() {
return HashUtil.shortHash(getHash().getBytes());
}
Expand Down Expand Up @@ -541,4 +573,8 @@ public byte[] getMiningForkDetectionData() {
public boolean isParentOf(BlockHeader header) {
return this.getHash().equals(header.getParentHash());
}

public byte[] getUmmRoot() {
return ummRoot != null ? Arrays.copyOf(ummRoot, ummRoot.length) : null;
}
}
30 changes: 28 additions & 2 deletions rskj-core/src/main/java/org/ethereum/core/BlockHeaderBuilder.java
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ public class BlockHeaderBuilder {
private byte[] bitcoinMergedMiningMerkleProof;
private byte[] bitcoinMergedMiningCoinbaseTransaction;
private byte[] mergedMiningForkDetectionData;
private byte[] ummRoot;

private Coin minimumGasPrice;
private int uncleCount;
Expand All @@ -66,17 +67,24 @@ public class BlockHeaderBuilder {
private final ActivationConfig activationConfig;

private boolean createConsensusCompliantHeader;
private boolean createUmmCompliantHeader;

public BlockHeaderBuilder(ActivationConfig activationConfig) {
this.activationConfig = activationConfig;
createConsensusCompliantHeader = true;
createUmmCompliantHeader = true;
}

public BlockHeaderBuilder setCreateConsensusCompliantHeader(boolean createConsensusCompliantHeader) {
this.createConsensusCompliantHeader = createConsensusCompliantHeader;
return this;
}

public BlockHeaderBuilder setCreateUmmCompliantHeader(boolean createUmmCompliantHeader) {
this.createUmmCompliantHeader = createUmmCompliantHeader;
return this;
}

public BlockHeaderBuilder setStateRoot(byte[] stateRoot) {
this.stateRoot = copy(stateRoot);
return this;
Expand Down Expand Up @@ -239,6 +247,11 @@ public BlockHeaderBuilder setEmptyReceiptTrieRoot() {
return this;
}

public BlockHeaderBuilder setUmmRoot(byte[] ummRoot) {
this.ummRoot = copy(ummRoot, null);
return this;
}

private void initializeWithDefaultValues() {
extraData = normalizeValue(extraData, new byte[0]);
bitcoinMergedMiningHeader = normalizeValue(bitcoinMergedMiningHeader, new byte[0]);
Expand Down Expand Up @@ -266,8 +279,12 @@ private byte[] copy(Keccak256 hash) {
}

private byte[] copy(byte[] bytes) {
return copy(bytes, new byte[0]);
}

private byte[] copy(byte[] bytes, byte[] defaultValue) {
if (bytes == null) {
return new byte[0];
return defaultValue;
}

return Arrays.copyOf(bytes, bytes.length);
Expand All @@ -277,12 +294,21 @@ public BlockHeader build() {
// Initial null values in some fields are replaced by empty
// arrays
initializeWithDefaultValues();

if (createConsensusCompliantHeader) {
useRskip92Encoding = activationConfig.isActive(ConsensusRule.RSKIP92, number);
includeForkDetectionData = activationConfig.isActive(ConsensusRule.RSKIP110, number) &&
mergedMiningForkDetectionData.length > 0;
}

if (createUmmCompliantHeader) {
if (activationConfig.isActive(ConsensusRule.RSKIPUMM, number)) {
if (ummRoot == null) {
ummRoot = new byte[0];
}
}
}

return new BlockHeader(
parentHash, unclesHash, coinbase,
stateRoot, txTrieRoot, receiptTrieRoot,
Expand All @@ -294,7 +320,7 @@ public BlockHeader build() {
mergedMiningForkDetectionData,
minimumGasPrice, uncleCount,
false, useRskip92Encoding,
includeForkDetectionData
includeForkDetectionData, ummRoot
);
}
}
6 changes: 4 additions & 2 deletions rskj-core/src/main/java/org/ethereum/core/GenesisHeader.java
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,8 @@ public GenesisHeader(byte[] parentHash,
0,
false,
useRskip92Encoding,
false);
false,
null);
this.difficulty = ByteUtils.clone(difficulty);
}

Expand Down Expand Up @@ -93,7 +94,8 @@ public GenesisHeader(byte[] parentHash,
0,
false,
useRskip92Encoding,
false);
false,
null);
this.difficulty = ByteUtils.clone(difficulty);
}

Expand Down
1 change: 1 addition & 0 deletions rskj-core/src/main/resources/reference.conf
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ blockchain = {
rskip151 = papyrus200,
rskip152 = papyrus200
rskip156 = papyrus200
rskipUMM = papyrus200
}
}
gc = {
Expand Down
Loading

0 comments on commit 32dbe67

Please sign in to comment.