Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support bsc bohr upgrade #43

Merged
merged 6 commits into from
Sep 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion bmv/bsc2/build.gradle
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
version = '0.6.1'
version = '0.7.2'

dependencies {
compileOnly("foundation.icon:javaee-api:$javaeeVersion")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,8 @@ public class BTPMessageVerifier implements BMV {
private final DictDB<byte[], Header> heads = Context.newDictDB("heads", Header.class);

public BTPMessageVerifier(Address _bmc, BigInteger _chainId, @Optional byte[] _header,
@Optional byte[] _validators, @Optional byte[] _candidates, @Optional byte[] _recents) {
@Optional byte[] _validators, @Optional byte[] _candidates,
@Optional byte[] _recents, @Optional int _currTurnLength, @Optional int _nextTurnLength) {
ChainConfig config = ChainConfig.setChainID(_chainId);
if (_header != null) {
Header head = Header.fromBytes(_header);
Expand All @@ -53,13 +54,14 @@ public BTPMessageVerifier(Address _bmc, BigInteger _chainId, @Optional byte[] _h
MerkleTreeAccumulator mta = new MerkleTreeAccumulator(head.getNumber().longValueExact());
mta.add(head.getHash().toBytes());

Context.require(_currTurnLength > 0 && _nextTurnLength > 0, "Invalid turn lengths");
Validators validators = Validators.fromBytes(_validators);
EthAddresses recents = EthAddresses.fromBytes(_recents);
if (head.getNumber().compareTo(BigInteger.ZERO) == 0) {
Context.require(recents.size() == 1, "Wrong recent signers");
} else {
Context.require(recents.size() == validators.size() / 2 + 1,
"Wrong recent signers - validators/2+1");
Context.require(recents.size() == Utils.calcMinerHistoryLength(validators.size(),
_currTurnLength) + 1, "Wrong recent signer counts");
}

this.bmc.set(_bmc);
Expand All @@ -75,15 +77,15 @@ public BTPMessageVerifier(Address _bmc, BigInteger _chainId, @Optional byte[] _h
Validators.fromBytes(_candidates),
Validators.fromBytes(_validators),
EthAddresses.fromBytes(_recents),
attestation));
attestation, _currTurnLength, _nextTurnLength));
} else {
Context.require(_bmc.equals(this.bmc.get()), "Mismatch BMC address");
}
}

@External(readonly = true)
public String getVersion() {
return "0.5.0";
return "0.7.2";
}

@External(readonly = true)
Expand Down Expand Up @@ -300,7 +302,7 @@ private void verify(ChainConfig config, Header head) {
Context.require(head.getGasLimit().compareTo(MIN_GAS_LIMIT) >= 0, "Invalid gas limit(< min)");
Context.require(head.getGasLimit().compareTo(MAX_GAS_LIMIT) <= 0, "Invalid gas limit(> max)");
Context.require(head.getGasUsed().compareTo(head.getGasLimit()) < 0, "Invalid gas used");
Context.require(head.getSigner(BigInteger.valueOf(config.ChainID)).equals(head.getCoinbase()), "Coinbase mismatch");
Context.require(head.getSigner(config, BigInteger.valueOf(config.ChainID)).equals(head.getCoinbase()), "Coinbase mismatch");

if (config.isTycho(head.getTime())) {
Context.require(head.getWithdrawalsHash().equals(EMPTY_WITHDRAWALS_HASH), "Invalid withdrawals hash");
Expand Down Expand Up @@ -384,7 +386,7 @@ private long getBackOffTime(Snapshot snap, Header head) {
Validators vals = snap.getValidators();
long number = head.getNumber().longValue();
EthAddress inturn = vals.get((int)(number % (long)vals.size())).getAddress();
if (snap.getRecents().contains(inturn)) {
if (snap.isRecentlySigned(inturn)) {
return 0L;
}
return DEFAULT_BACKOFF_TIME;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ public class ChainConfig {
public final long Period;
public final BigInteger Hertz;
public final BigInteger Tycho;
public final BigInteger Bohr;

private static ChainConfig instance;

Expand All @@ -35,12 +36,13 @@ public static ChainConfig setChainID(BigInteger cid) {
return instance;
}

private ChainConfig(long chainId, long epoch, long period, BigInteger hertz, BigInteger tycho) {
private ChainConfig(long chainId, long epoch, long period, BigInteger hertz, BigInteger tycho, BigInteger bohr) {
this.ChainID = chainId;
this.Epoch = epoch;
this.Period = period;
this.Hertz = hertz;
this.Tycho = tycho;
this.Bohr = bohr;
}

public static ChainConfig getInstance() {
Expand All @@ -51,14 +53,14 @@ public static ChainConfig fromChainID(BigInteger cid) {
if (cid.longValue() == 56L) {
// BSC Mainnet
return new ChainConfig(56L, 200L, 3L, BigInteger.valueOf(31302048L),
BigInteger.valueOf(1718863500L));
BigInteger.valueOf(1718863500L), BigInteger.valueOf(1727317200L));
} else if (cid.longValue() == 97L) {
// BSC Testnet
return new ChainConfig(97L, 200L, 3L, BigInteger.valueOf(31103030L),
BigInteger.valueOf(1713330442L));
BigInteger.valueOf(1713330442L), BigInteger.valueOf(1724116996L));
} else if (cid.longValue() == 99L) {
// Private BSC Testnet
return new ChainConfig(99L, 200L, 3L, BigInteger.valueOf(8), null);
return new ChainConfig(99L, 200L, 3L, BigInteger.valueOf(8), null, null);
}

Context.require(false, "No Chain Config - ChainID(" + cid.intValue() + ")");
Expand All @@ -77,4 +79,8 @@ public boolean isTycho(long time) {
return Tycho != null && Tycho.longValue() <= time;
}

public boolean isBohr(long time) {
return Bohr != null && Bohr.longValue() <= time;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@

public class EthAddress implements Comparable<EthAddress> {
public static final int LENGTH = 20;
public static final EthAddress EMPTY = new EthAddress(new byte[LENGTH]);

private final byte[] data;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,10 +57,28 @@ public EthAddress remove(int i) {
return addresses.remove(i);
}

public EthAddress set(int i, EthAddress v) {
return addresses.set(i, v);
}

public int size() {
return addresses.size();
}

public int count(EthAddress cmp) {
int cnt = 0;
for (EthAddress address : addresses) {
if (address.equals(cmp)) {
cnt++;
}
}
return cnt;
}

public void clear() {
addresses.clear();
}

@Override
public String toString() {
return "EthAddresses{" +
Expand Down
95 changes: 73 additions & 22 deletions bmv/bsc2/src/main/java/foundation/icon/btp/bmv/bsc2/Header.java
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ public class Header {
public static final int EXTRA_SEAL = 65;
public static final int VALIDATOR_NUMBER_SIZE = 1;
public static final int VALIDATOR_BYTES_LENGTH = EthAddress.LENGTH + BLSPublicKey.LENGTH;
public static final int TURN_LENGTH_SIZE = 1;
// pre-calculated constant uncle hash:) rlp([])
public static final Hash UNCLE_HASH =
Hash.of("1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347");
Expand All @@ -41,6 +42,7 @@ public class Header {
public static final BigInteger GAS_LIMIT_BOUND_DIVISOR = BigInteger.valueOf(256L);
public static final BigInteger MAX_GAS_LIMIT = BigInteger.valueOf(0x7FFFFFFFFFFFFFFFL); // (2^63-1)
public static final BigInteger MIN_GAS_LIMIT = BigInteger.valueOf(5000L);
public static final int DEFAULT_TURN_LENGTH = 1;

private final Hash parentHash;
private final Hash uncleHash;
Expand All @@ -61,6 +63,7 @@ public class Header {
private final Hash withdrawalsHash;
private final BigInteger blobGasUsed;
private final BigInteger excessBlobGas;
private final Hash parentBeaconRoot;

// caches
private Hash hashCache;
Expand Down Expand Up @@ -92,6 +95,7 @@ public Header(Hash parentHash, Hash uncleHash, EthAddress coinbase, Hash root,
this.withdrawalsHash = withdrawalsHash;
this.blobGasUsed = blobGasUsed;
this.excessBlobGas = excessBlobGas;
this.parentBeaconRoot = Hash.EMPTY;
}

public static Header readObject(ObjectReader r) {
Expand Down Expand Up @@ -135,7 +139,9 @@ public static Header readObject(ObjectReader r) {
}

public static void writeObject(ObjectWriter w, Header o) {
if (ChainConfig.getInstance().isTycho(o.time)) {
if (ChainConfig.getInstance().isBohr(o.time)) {
w.beginList(20);
} else if (ChainConfig.getInstance().isTycho(o.time)) {
w.beginList(19);
} else if (ChainConfig.getInstance().isHertz(o.number)) {
w.beginList(16);
Expand Down Expand Up @@ -168,6 +174,9 @@ public static void writeObject(ObjectWriter w, Header o) {
w.write(o.blobGasUsed);
w.write(o.excessBlobGas);
}
if (ChainConfig.getInstance().isBohr(o.time)) {
w.write(o.parentBeaconRoot);
}
w.end();
}

Expand Down Expand Up @@ -232,6 +241,9 @@ public VoteAttestation getVoteAttestation(ChainConfig config) {
return null;
}
int start = EXTRA_VANITY + VALIDATOR_NUMBER_SIZE + num * VALIDATOR_BYTES_LENGTH;
if (config.isBohr(time)) {
start += TURN_LENGTH_SIZE;
}
int end = extra.length - EXTRA_SEAL;
blob = Arrays.copyOfRange(extra, start, end);
}
Expand All @@ -240,34 +252,73 @@ public VoteAttestation getVoteAttestation(ChainConfig config) {
return atteCache;
}

public EthAddress getSigner(BigInteger cid) {
public int getTurnLength(ChainConfig config) {
Context.require(config.isEpoch(number), "no turn length");
if (!config.isBohr(time)) {
return DEFAULT_TURN_LENGTH;
}

Context.require(extra.length > EXTRA_VANITY + EXTRA_SEAL, "too short extra data for including turn length");
int num = extra[EXTRA_VANITY];
int pos = EXTRA_VANITY + VALIDATOR_NUMBER_SIZE + num * VALIDATOR_BYTES_LENGTH;
Context.require(extra.length > pos, "no field for turn length");
return extra[pos];
}

public EthAddress getSigner(ChainConfig config, BigInteger cid) {
Context.require(extra.length >= EXTRA_SEAL, "Invalid seal bytes");
byte[] signature = Arrays.copyOfRange(extra, extra.length - EXTRA_SEAL, extra.length);
byte[] pubkey = Context.recoverKey("ecdsa-secp256k1", getSealHash(cid), signature, false);
byte[] pubkey = Context.recoverKey("ecdsa-secp256k1", getSealHash(config, cid), signature, false);
byte[] pubhash = Context.hash("keccak-256", Arrays.copyOfRange(pubkey, 1, pubkey.length));
return new EthAddress(Arrays.copyOfRange(pubhash, 12, pubhash.length));
}

private byte[] getSealHash(BigInteger cid) {
private byte[] getSealHash(ChainConfig config, BigInteger cid) {
ByteArrayObjectWriter w = Context.newByteArrayObjectWriter("RLP");
w.beginList(16);
w.write(cid);
w.write(parentHash);
w.write(uncleHash);
w.write(coinbase);
w.write(root);
w.write(txHash);
w.write(receiptHash);
w.write(bloom);
w.write(difficulty);
w.write(number);
w.write(gasLimit);
w.write(gasUsed);
w.write(time);
w.write(Arrays.copyOfRange(extra, 0, extra.length-65));
w.write(mixDigest);
w.write(nonce);
w.end();
if (config.isBohr(time)) {
w.beginList(21);
w.write(cid);
w.write(parentHash);
w.write(uncleHash);
w.write(coinbase);
w.write(root);
w.write(txHash);
w.write(receiptHash);
w.write(bloom);
w.write(difficulty);
w.write(number);
w.write(gasLimit);
w.write(gasUsed);
w.write(time);
w.write(Arrays.copyOfRange(extra, 0, extra.length-65));
w.write(mixDigest);
w.write(nonce);
w.write(baseFee);
w.write(withdrawalsHash);
w.write(blobGasUsed);
w.write(excessBlobGas);
w.write(parentBeaconRoot);
w.end();
} else {
w.beginList(16);
w.write(cid);
w.write(parentHash);
w.write(uncleHash);
w.write(coinbase);
w.write(root);
w.write(txHash);
w.write(receiptHash);
w.write(bloom);
w.write(difficulty);
w.write(number);
w.write(gasLimit);
w.write(gasUsed);
w.write(time);
w.write(Arrays.copyOfRange(extra, 0, extra.length-65));
w.write(mixDigest);
w.write(nonce);
w.end();
}
return Context.hash("keccak-256", w.toByteArray());
}

Expand Down
Loading
Loading