diff --git a/ethereum/eth/src/main/java/tech/pegasys/pantheon/ethereum/eth/sync/worldstate/AccountTrieNodeDataRequest.java b/ethereum/eth/src/main/java/tech/pegasys/pantheon/ethereum/eth/sync/worldstate/AccountTrieNodeDataRequest.java index fcdb9df8e1..c261b0e026 100644 --- a/ethereum/eth/src/main/java/tech/pegasys/pantheon/ethereum/eth/sync/worldstate/AccountTrieNodeDataRequest.java +++ b/ethereum/eth/src/main/java/tech/pegasys/pantheon/ethereum/eth/sync/worldstate/AccountTrieNodeDataRequest.java @@ -27,7 +27,7 @@ import java.util.List; class AccountTrieNodeDataRequest extends TrieNodeDataRequest { AccountTrieNodeDataRequest(final Hash hash) { - super(Kind.ACCOUNT_TRIE_NODE, hash); + super(RequestType.ACCOUNT_TRIE_NODE, hash); } @Override diff --git a/ethereum/eth/src/main/java/tech/pegasys/pantheon/ethereum/eth/sync/worldstate/CodeNodeDataRequest.java b/ethereum/eth/src/main/java/tech/pegasys/pantheon/ethereum/eth/sync/worldstate/CodeNodeDataRequest.java index 0466252281..c4825873f4 100644 --- a/ethereum/eth/src/main/java/tech/pegasys/pantheon/ethereum/eth/sync/worldstate/CodeNodeDataRequest.java +++ b/ethereum/eth/src/main/java/tech/pegasys/pantheon/ethereum/eth/sync/worldstate/CodeNodeDataRequest.java @@ -22,7 +22,7 @@ import java.util.stream.Stream; class CodeNodeDataRequest extends NodeDataRequest { CodeNodeDataRequest(final Hash hash) { - super(Kind.CODE, hash); + super(RequestType.CODE, hash); } @Override diff --git a/ethereum/eth/src/main/java/tech/pegasys/pantheon/ethereum/eth/sync/worldstate/NodeDataRequest.java b/ethereum/eth/src/main/java/tech/pegasys/pantheon/ethereum/eth/sync/worldstate/NodeDataRequest.java index 67b7a63ae5..6092661046 100644 --- a/ethereum/eth/src/main/java/tech/pegasys/pantheon/ethereum/eth/sync/worldstate/NodeDataRequest.java +++ b/ethereum/eth/src/main/java/tech/pegasys/pantheon/ethereum/eth/sync/worldstate/NodeDataRequest.java @@ -13,24 +13,22 @@ package tech.pegasys.pantheon.ethereum.eth.sync.worldstate; import tech.pegasys.pantheon.ethereum.core.Hash; +import tech.pegasys.pantheon.ethereum.rlp.RLP; +import tech.pegasys.pantheon.ethereum.rlp.RLPInput; +import tech.pegasys.pantheon.ethereum.rlp.RLPOutput; import tech.pegasys.pantheon.ethereum.worldstate.WorldStateStorage; import tech.pegasys.pantheon.util.bytes.BytesValue; import java.util.stream.Stream; -abstract class NodeDataRequest { - public enum Kind { - ACCOUNT_TRIE_NODE, - STORAGE_TRIE_NODE, - CODE - } +public abstract class NodeDataRequest { - private final Kind kind; + private final RequestType requestType; private final Hash hash; private BytesValue data; - protected NodeDataRequest(final Kind kind, final Hash hash) { - this.kind = kind; + protected NodeDataRequest(final RequestType requestType, final Hash hash) { + this.requestType = requestType; this.hash = hash; } @@ -46,8 +44,40 @@ abstract class NodeDataRequest { return new CodeNodeDataRequest(hash); } - public Kind getKind() { - return kind; + public static BytesValue serialize(final NodeDataRequest request) { + return RLP.encode(request::writeTo); + } + + public static NodeDataRequest deserialize(final BytesValue encoded) { + RLPInput in = RLP.input(encoded); + in.enterList(); + RequestType requestType = RequestType.fromValue(in.readByte()); + Hash hash = Hash.wrap(in.readBytes32()); + in.leaveList(); + + switch (requestType) { + case ACCOUNT_TRIE_NODE: + return createAccountDataRequest(hash); + case STORAGE_TRIE_NODE: + return createStorageDataRequest(hash); + case CODE: + return createCodeRequest(hash); + default: + throw new IllegalArgumentException( + "Unable to deserialize provided data into a valid " + + NodeDataRequest.class.getSimpleName()); + } + } + + private void writeTo(final RLPOutput out) { + out.startList(); + out.writeByte(requestType.getValue()); + out.writeBytesValue(hash); + out.endList(); + } + + public RequestType getRequestType() { + return requestType; } public Hash getHash() { diff --git a/ethereum/eth/src/main/java/tech/pegasys/pantheon/ethereum/eth/sync/worldstate/RequestType.java b/ethereum/eth/src/main/java/tech/pegasys/pantheon/ethereum/eth/sync/worldstate/RequestType.java new file mode 100644 index 0000000000..46f121f669 --- /dev/null +++ b/ethereum/eth/src/main/java/tech/pegasys/pantheon/ethereum/eth/sync/worldstate/RequestType.java @@ -0,0 +1,42 @@ +/* + * Copyright 2019 ConsenSys AG. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ +package tech.pegasys.pantheon.ethereum.eth.sync.worldstate; + +public enum RequestType { + ACCOUNT_TRIE_NODE((byte) 1), + STORAGE_TRIE_NODE((byte) 2), + CODE((byte) 3); + + private final byte value; + + RequestType(final byte value) { + this.value = value; + } + + public byte getValue() { + return value; + } + + public static RequestType fromValue(final byte value) { + switch (value) { + case (byte) 1: + return ACCOUNT_TRIE_NODE; + case (byte) 2: + return STORAGE_TRIE_NODE; + case (byte) 3: + return CODE; + default: + throw new IllegalArgumentException("Invalid value supplied"); + } + } +} diff --git a/ethereum/eth/src/main/java/tech/pegasys/pantheon/ethereum/eth/sync/worldstate/StorageTrieNodeDataRequest.java b/ethereum/eth/src/main/java/tech/pegasys/pantheon/ethereum/eth/sync/worldstate/StorageTrieNodeDataRequest.java index d61292a066..a725df43e2 100644 --- a/ethereum/eth/src/main/java/tech/pegasys/pantheon/ethereum/eth/sync/worldstate/StorageTrieNodeDataRequest.java +++ b/ethereum/eth/src/main/java/tech/pegasys/pantheon/ethereum/eth/sync/worldstate/StorageTrieNodeDataRequest.java @@ -24,7 +24,7 @@ import java.util.List; class StorageTrieNodeDataRequest extends TrieNodeDataRequest { StorageTrieNodeDataRequest(final Hash hash) { - super(Kind.STORAGE_TRIE_NODE, hash); + super(RequestType.STORAGE_TRIE_NODE, hash); } @Override diff --git a/ethereum/eth/src/main/java/tech/pegasys/pantheon/ethereum/eth/sync/worldstate/TrieNodeDataRequest.java b/ethereum/eth/src/main/java/tech/pegasys/pantheon/ethereum/eth/sync/worldstate/TrieNodeDataRequest.java index abf9bbd512..a4e771ae30 100644 --- a/ethereum/eth/src/main/java/tech/pegasys/pantheon/ethereum/eth/sync/worldstate/TrieNodeDataRequest.java +++ b/ethereum/eth/src/main/java/tech/pegasys/pantheon/ethereum/eth/sync/worldstate/TrieNodeDataRequest.java @@ -24,7 +24,7 @@ abstract class TrieNodeDataRequest extends NodeDataRequest { private static final TrieNodeDecoder nodeDecoder = TrieNodeDecoder.create(); - TrieNodeDataRequest(final Kind kind, final Hash hash) { + TrieNodeDataRequest(final RequestType kind, final Hash hash) { super(kind, hash); } diff --git a/ethereum/eth/src/test/java/tech/pegasys/pantheon/ethereum/eth/sync/worldstate/NodeDataRequestTest.java b/ethereum/eth/src/test/java/tech/pegasys/pantheon/ethereum/eth/sync/worldstate/NodeDataRequestTest.java new file mode 100644 index 0000000000..52bd33bddf --- /dev/null +++ b/ethereum/eth/src/test/java/tech/pegasys/pantheon/ethereum/eth/sync/worldstate/NodeDataRequestTest.java @@ -0,0 +1,59 @@ +/* + * Copyright 2019 ConsenSys AG. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ +package tech.pegasys.pantheon.ethereum.eth.sync.worldstate; + +import static org.assertj.core.api.Assertions.assertThat; + +import tech.pegasys.pantheon.ethereum.core.BlockDataGenerator; + +import org.junit.Test; + +public class NodeDataRequestTest { + + @Test + public void serializesAccountTrieNodeRequests() { + BlockDataGenerator gen = new BlockDataGenerator(0); + AccountTrieNodeDataRequest request = NodeDataRequest.createAccountDataRequest(gen.hash()); + NodeDataRequest sedeRequest = serializeThenDeserialize(request); + assertRequestsEquals(sedeRequest, request); + assertThat(sedeRequest).isInstanceOf(AccountTrieNodeDataRequest.class); + } + + @Test + public void serializesStorageTrieNodeRequests() { + BlockDataGenerator gen = new BlockDataGenerator(0); + StorageTrieNodeDataRequest request = NodeDataRequest.createStorageDataRequest(gen.hash()); + NodeDataRequest sedeRequest = serializeThenDeserialize(request); + assertRequestsEquals(sedeRequest, request); + assertThat(sedeRequest).isInstanceOf(StorageTrieNodeDataRequest.class); + } + + @Test + public void serializesCodeRequests() { + BlockDataGenerator gen = new BlockDataGenerator(0); + CodeNodeDataRequest request = NodeDataRequest.createCodeRequest(gen.hash()); + NodeDataRequest sedeRequest = serializeThenDeserialize(request); + assertRequestsEquals(sedeRequest, request); + assertThat(sedeRequest).isInstanceOf(CodeNodeDataRequest.class); + } + + private NodeDataRequest serializeThenDeserialize(final NodeDataRequest request) { + return NodeDataRequest.deserialize(NodeDataRequest.serialize(request)); + } + + private void assertRequestsEquals(final NodeDataRequest actual, final NodeDataRequest expected) { + assertThat(actual.getRequestType()).isEqualTo(expected.getRequestType()); + assertThat(actual.getHash()).isEqualTo(expected.getHash()); + assertThat(actual.getData()).isEqualTo(expected.getData()); + } +}