Skip to content
This repository has been archived by the owner on Sep 26, 2019. It is now read-only.

Large chain id support for private transactions #1452

Merged
merged 3 commits into from
May 17, 2019
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
Next Next commit
large chain id support for private transactions
  • Loading branch information
jframe committed May 16, 2019
commit 0d6e37fca06d8ad3853dd8f36e7b4ec0b1d369de
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import tech.pegasys.pantheon.ethereum.rlp.RLP;
import tech.pegasys.pantheon.util.bytes.BytesValue;

import java.math.BigInteger;
import java.util.List;

public class PrivateTransactionBuilder {
Expand Down Expand Up @@ -124,7 +125,7 @@ public String build(final TransactionType type) {
.value(Wei.ZERO)
.payload(payload)
.sender(from)
.chainId(2018)
.chainId(BigInteger.valueOf(2018))
.privateFrom(privateFrom)
.privateFor(privateFor)
.restriction(BytesValue.wrap("restricted".getBytes(UTF_8)))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,20 +33,22 @@
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.OptionalInt;

/** An operation submitted by an external actor to be applied to the system. */
public class PrivateTransaction {

// Used for transactions that are not tied to a specific chain
// (e.g. does not have a chain id associated with it).
private static final int REPLAY_UNPROTECTED_V_BASE = 27;
private static final BigInteger REPLAY_UNPROTECTED_V_BASE = BigInteger.valueOf(27);
private static final BigInteger REPLAY_UNPROTECTED_V_BASE_PLUS_1 = BigInteger.valueOf(28);

private static final int REPLAY_PROTECTED_V_BASE = 35;
private static final BigInteger REPLAY_PROTECTED_V_BASE = BigInteger.valueOf(35);

// The v signature parameter starts at 36 because 1 is the first valid chainId so:
// chainId > 1 implies that 2 * chainId + V_BASE > 36.
private static final int REPLAY_PROTECTED_V_MIN = 36;
private static final BigInteger REPLAY_PROTECTED_V_MIN = BigInteger.valueOf(36);

private static final BigInteger TWO = BigInteger.valueOf(2);

private final long nonce;

Expand All @@ -62,7 +64,7 @@ public class PrivateTransaction {

private final BytesValue payload;

private final OptionalInt chainId;
private final Optional<BigInteger> chainId;

private final BytesValue privateFrom;

Expand Down Expand Up @@ -98,14 +100,14 @@ public static PrivateTransaction readFrom(final RLPInput input) throws RLPExcept
.value(input.readUInt256Scalar(Wei::wrap))
.payload(input.readBytesValue());

final int v = input.readIntScalar();
final BigInteger v = input.readBigIntegerScalar();
final byte recId;
int chainId = -1;
if (v == REPLAY_UNPROTECTED_V_BASE || v == REPLAY_UNPROTECTED_V_BASE + 1) {
recId = (byte) (v - REPLAY_UNPROTECTED_V_BASE);
} else if (v > REPLAY_PROTECTED_V_MIN) {
chainId = (v - REPLAY_PROTECTED_V_BASE) / 2;
recId = (byte) (v - (2 * chainId + REPLAY_PROTECTED_V_BASE));
Optional<BigInteger> chainId = Optional.empty();
if (v.equals(REPLAY_UNPROTECTED_V_BASE) || v.equals(REPLAY_UNPROTECTED_V_BASE_PLUS_1)) {
recId = v.subtract(REPLAY_UNPROTECTED_V_BASE).byteValueExact();
} else if (v.compareTo(REPLAY_PROTECTED_V_MIN) > 0) {
chainId = Optional.of(v.subtract(REPLAY_PROTECTED_V_BASE).divide(TWO));
recId = v.subtract(TWO.multiply(chainId.get()).add(REPLAY_PROTECTED_V_BASE)).byteValueExact();
} else {
throw new RuntimeException(
String.format("An unsupported encoded `v` value of %s was found", v));
Expand All @@ -119,8 +121,8 @@ public static PrivateTransaction readFrom(final RLPInput input) throws RLPExcept

input.leaveList();

chainId.ifPresent(builder::chainId);
return builder
.chainId(chainId)
.signature(signature)
.privateFrom(privateFrom)
.privateFor(privateFor)
Expand Down Expand Up @@ -158,7 +160,7 @@ protected PrivateTransaction(
final SECP256K1.Signature signature,
final BytesValue payload,
final Address sender,
final int chainId,
final Optional<BigInteger> chainId,
final BytesValue privateFrom,
final List<BytesValue> privateFor,
final BytesValue restriction) {
Expand All @@ -170,7 +172,7 @@ protected PrivateTransaction(
this.signature = signature;
this.payload = payload;
this.sender = sender;
this.chainId = chainId > 0 ? OptionalInt.of(chainId) : OptionalInt.empty();
this.chainId = chainId;
this.privateFrom = privateFrom;
this.privateFor = privateFor;
this.restriction = restriction;
Expand Down Expand Up @@ -250,7 +252,7 @@ public BytesValue getPayload() {
*
* @return the transaction chain id if it exists; otherwise {@code OptionalInt.empty()}
*/
public OptionalInt getChainId() {
public Optional<BigInteger> getChainId() {
return chainId;
}

Expand Down Expand Up @@ -340,7 +342,7 @@ public void writeTo(final RLPOutput out) {
}

private void writeSignature(final RLPOutput out) {
out.writeIntScalar(getV());
out.writeBigIntegerScalar(getV());
out.writeBigIntegerScalar(getSignature().getR());
out.writeBigIntegerScalar(getSignature().getS());
}
Expand All @@ -353,12 +355,13 @@ public BigInteger getS() {
return signature.getS();
}

public int getV() {
final int v;
public BigInteger getV() {
final BigInteger v;
final BigInteger recId = BigInteger.valueOf(signature.getRecId());
if (!chainId.isPresent()) {
v = signature.getRecId() + REPLAY_UNPROTECTED_V_BASE;
v = recId.add(REPLAY_UNPROTECTED_V_BASE);
} else {
v = (getSignature().getRecId() + REPLAY_PROTECTED_V_BASE + 2 * chainId.getAsInt());
v = recId.add(REPLAY_PROTECTED_V_BASE).add(TWO.multiply(chainId.get()));
}
return v;
}
Expand Down Expand Up @@ -414,7 +417,7 @@ private static Bytes32 computeSenderRecoveryHash(
final Address to,
final Wei value,
final BytesValue payload,
final OptionalInt chainId,
final Optional<BigInteger> chainId,
final BytesValue privateFrom,
final List<BytesValue> privateFor,
final BytesValue restriction) {
Expand All @@ -429,7 +432,7 @@ private static Bytes32 computeSenderRecoveryHash(
out.writeUInt256Scalar(value);
out.writeBytesValue(payload);
if (chainId.isPresent()) {
out.writeIntScalar(chainId.getAsInt());
out.writeBigIntegerScalar(chainId.get());
out.writeUInt256Scalar(UInt256.ZERO);
out.writeUInt256Scalar(UInt256.ZERO);
}
Expand Down Expand Up @@ -485,7 +488,7 @@ public String toString() {
if (getTo().isPresent()) sb.append("to=").append(getTo().get()).append(", ");
sb.append("value=").append(getValue()).append(", ");
sb.append("sig=").append(getSignature()).append(", ");
if (chainId.isPresent()) sb.append("chainId=").append(getChainId().getAsInt()).append(", ");
if (chainId.isPresent()) sb.append("chainId=").append(getChainId().get()).append(", ");
sb.append("payload=").append(getPayload());
sb.append("privateFrom=").append(getPrivateFrom());
sb.append("privateFor=").append(Arrays.toString(getPrivateFor().toArray()));
Expand Down Expand Up @@ -518,16 +521,16 @@ public static class Builder {

protected Address sender;

protected int chainId = -1;
protected Optional<BigInteger> chainId = Optional.empty();

protected BytesValue privateFrom;

protected List<BytesValue> privateFor;

protected BytesValue restriction;

public Builder chainId(final int chainId) {
this.chainId = chainId;
public Builder chainId(final BigInteger chainId) {
this.chainId = Optional.of(chainId);
return this;
}

Expand Down Expand Up @@ -611,8 +614,6 @@ public PrivateTransaction signAndBuild(final SECP256K1.KeyPair keys) {
}

protected SECP256K1.Signature computeSignature(final SECP256K1.KeyPair keys) {
final OptionalInt optionalChainId =
chainId > 0 ? OptionalInt.of(chainId) : OptionalInt.empty();
final Bytes32 hash =
computeSenderRecoveryHash(
nonce,
Expand All @@ -621,7 +622,7 @@ protected SECP256K1.Signature computeSignature(final SECP256K1.KeyPair keys) {
to,
value,
payload,
optionalChainId,
chainId,
privateFrom,
privateFor,
restriction);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ public class PrivateTransactionHandlerTest {
.value(Wei.ZERO)
.payload(BytesValue.fromHexString("0x"))
.sender(Address.fromHexString("0xfe3b557e8fb62b89f4916b721be55ceb828dbd73"))
.chainId(2018)
.chainId(BigInteger.valueOf(2018))
.privateFrom(
BytesValue.wrap("A1aVtMxLCUHmBVHXoZzzBgPbW/wj5axDpW9X8l91SGo=".getBytes(UTF_8)))
.privateFor(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ public class PrivateTransactionTest {
Byte.valueOf("0")),
BytesValue.fromHexString("0x"),
Address.wrap(BytesValue.fromHexString("0x8411b12666f68ef74cace3615c9d5a377729d03f")),
0,
Optional.empty(),
BytesValue.wrap("A1aVtMxLCUHmBVHXoZzzBgPbW/wj5axDpW9X8l91SGo=".getBytes(UTF_8)),
Lists.newArrayList(
BytesValue.wrap("A1aVtMxLCUHmBVHXoZzzBgPbW/wj5axDpW9X8l91SGo=".getBytes(UTF_8)),
Expand Down Expand Up @@ -113,7 +113,7 @@ public class PrivateTransactionTest {
+ "0029"))
.sender(
Address.wrap(BytesValue.fromHexString("0x1c9a6e1ee3b7ac6028e786d9519ae3d24ee31e79")))
.chainId(4)
.chainId(BigInteger.valueOf(4))
.privateFrom(
BytesValue.wrap("A1aVtMxLCUHmBVHXoZzzBgPbW/wj5axDpW9X8l91SGo=".getBytes(UTF_8)))
.privateFor(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ public class EeaGetTransactionReceiptTest {
+ "5820cb1d0935d14b589300b12fcd0ab849a7e9019c81da24d6"
+ "daa4f6b2f003d1b0180029"))
.sender(sender)
.chainId(2018)
.chainId(BigInteger.valueOf(2018))
.privateFrom(
BytesValue.wrap("A1aVtMxLCUHmBVHXoZzzBgPbW/wj5axDpW9X8l91SGo=".getBytes(UTF_8)))
.privateFor(
Expand Down