Skip to content

Commit 2cc97c1

Browse files
bullet-toothIlya Bogdanov
authored andcommitted
[ECR-4021] reflect proto changes for Block (#1350)
1 parent 6300899 commit 2cc97c1

File tree

5 files changed

+107
-1
lines changed

5 files changed

+107
-1
lines changed

exonum-java-binding/core/src/main/java/com/exonum/binding/core/blockchain/Block.java

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,10 @@
2222
import com.exonum.binding.core.blockchain.serialization.CoreTypeAdapterFactory;
2323
import com.exonum.binding.core.service.Schema;
2424
import com.google.auto.value.AutoValue;
25+
import com.google.common.collect.ImmutableMap;
2526
import com.google.gson.Gson;
2627
import com.google.gson.TypeAdapter;
28+
import com.google.protobuf.ByteString;
2729

2830
/**
2931
* Exonum block header data structure.
@@ -90,6 +92,19 @@ public final boolean isEmpty() {
9092
*/
9193
public abstract HashCode getStateHash();
9294

95+
/**
96+
* Root hash of exceptions occurred in the block.
97+
*
98+
* @see Blockchain#getCallErrors()
99+
*/
100+
public abstract HashCode getErrorHash();
101+
102+
/**
103+
* Contains additional block headers of the block.
104+
* The key is a block header; and the value is a header bytes value.
105+
*/
106+
public abstract ImmutableMap<String, ByteString> getAdditionalHeaders();
107+
93108
@Override
94109
public int hashCode() {
95110
// Use just the first 4 bytes of the SHA-256 hash of the binary object representation,
@@ -161,6 +176,19 @@ public abstract static class Builder {
161176
*/
162177
public abstract Builder stateHash(HashCode blockchainStateHash);
163178

179+
/**
180+
* Sets error hash.
181+
*
182+
* @see Blockchain#getCallErrors()
183+
*/
184+
public abstract Builder errorHash(HashCode errorHash);
185+
186+
/**
187+
* Sets additional block headers. Headers should have exactly the same order
188+
* as its native equivalent. Changing headers order will lead to the block hash violation.
189+
*/
190+
public abstract Builder additionalHeaders(ImmutableMap<String, ByteString> additionalHeaders);
191+
164192
abstract Block autoBuild();
165193

166194
/**

exonum-java-binding/core/src/main/java/com/exonum/binding/core/blockchain/serialization/BlockSerializer.java

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,21 @@
1717
package com.exonum.binding.core.blockchain.serialization;
1818

1919
import static com.exonum.binding.common.serialization.StandardSerializers.protobuf;
20+
import static com.google.common.collect.ImmutableMap.toImmutableMap;
2021

2122
import com.exonum.binding.common.hash.HashCode;
2223
import com.exonum.binding.common.hash.Hashing;
2324
import com.exonum.binding.common.serialization.Serializer;
2425
import com.exonum.binding.core.blockchain.Block;
2526
import com.exonum.core.messages.Blockchain;
27+
import com.exonum.core.messages.Blockchain.AdditionalHeaders;
28+
import com.exonum.core.messages.KeyValueSequenceOuterClass.KeyValue;
29+
import com.exonum.core.messages.KeyValueSequenceOuterClass.KeyValueSequence;
30+
import com.exonum.core.messages.KeyValueSequenceOuterClass.KeyValueSequence.Builder;
2631
import com.exonum.core.messages.Types;
2732
import com.exonum.core.messages.Types.Hash;
33+
import com.google.common.annotations.VisibleForTesting;
34+
import com.google.common.collect.ImmutableMap;
2835
import com.google.protobuf.ByteString;
2936

3037
public enum BlockSerializer implements Serializer<Block> {
@@ -42,6 +49,8 @@ public byte[] toBytes(Block value) {
4249
.setPrevHash(toHashProto(value.getPreviousBlockHash()))
4350
.setTxHash(toHashProto(value.getTxRootHash()))
4451
.setStateHash(toHashProto(value.getStateHash()))
52+
.setErrorHash(toHashProto(value.getErrorHash()))
53+
.setAdditionalHeaders(toHeadersProto(value.getAdditionalHeaders()))
4554
.build();
4655
return block.toByteArray();
4756
}
@@ -58,6 +67,8 @@ public Block fromBytes(byte[] binaryBlock) {
5867
.previousBlockHash(toHashCode(copiedBlocks.getPrevHash()))
5968
.txRootHash(toHashCode(copiedBlocks.getTxHash()))
6069
.stateHash(toHashCode(copiedBlocks.getStateHash()))
70+
.errorHash(toHashCode(copiedBlocks.getErrorHash()))
71+
.additionalHeaders(toHeadersMap(copiedBlocks.getAdditionalHeaders()))
6172
.build();
6273
}
6374

@@ -72,4 +83,30 @@ private static HashCode toHashCode(Hash hash) {
7283
ByteString bytes = hash.getData();
7384
return HashCode.fromBytes(bytes.toByteArray());
7485
}
86+
87+
@VisibleForTesting
88+
static ImmutableMap<String, ByteString> toHeadersMap(AdditionalHeaders headers) {
89+
return headers.getHeaders().getEntryList()
90+
.stream()
91+
.collect(toImmutableMap(KeyValue::getKey, KeyValue::getValue));
92+
}
93+
94+
@VisibleForTesting
95+
static AdditionalHeaders toHeadersProto(ImmutableMap<String, ByteString> headers) {
96+
Builder additionalHeadersBuilder = KeyValueSequence.newBuilder();
97+
98+
headers.forEach((k, v) -> additionalHeadersBuilder.addEntry(toProtoEntry(k, v)));
99+
100+
return AdditionalHeaders.newBuilder()
101+
.setHeaders(additionalHeadersBuilder.build())
102+
.build();
103+
}
104+
105+
private static KeyValue toProtoEntry(String key, ByteString value) {
106+
return KeyValue.newBuilder()
107+
.setKey(key)
108+
.setValue(value)
109+
.build();
110+
}
111+
75112
}

exonum-java-binding/core/src/test/java/com/exonum/binding/core/blockchain/BlockTest.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import com.exonum.binding.common.hash.HashFunction;
2525
import com.exonum.binding.common.hash.Hashing;
2626
import com.exonum.binding.core.blockchain.Block.Builder;
27+
import com.google.common.collect.ImmutableMap;
2728
import nl.jqno.equalsverifier.EqualsVerifier;
2829
import nl.jqno.equalsverifier.Warning;
2930
import org.junit.jupiter.api.Test;
@@ -72,6 +73,8 @@ private static Builder aBlock() {
7273
.blockHash(hashFunction.hashLong(blockHeight))
7374
.previousBlockHash(hashFunction.hashLong(blockHeight - 1))
7475
.txRootHash(hashFunction.hashString("transactions at" + blockHeight, UTF_8))
75-
.stateHash(hashFunction.hashString("state hash at " + blockHeight, UTF_8));
76+
.stateHash(hashFunction.hashString("state hash at " + blockHeight, UTF_8))
77+
.additionalHeaders(ImmutableMap.of())
78+
.errorHash(HashCode.fromString("ab"));
7679
}
7780
}

exonum-java-binding/core/src/test/java/com/exonum/binding/core/blockchain/Blocks.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@ public static Block withProperHash(Block block) {
4040
.previousBlockHash(block.getPreviousBlockHash())
4141
.txRootHash(block.getTxRootHash())
4242
.stateHash(block.getStateHash())
43+
.errorHash(block.getErrorHash())
44+
.additionalHeaders(block.getAdditionalHeaders())
4345
.build();
4446
}
4547

exonum-java-binding/core/src/test/java/com/exonum/binding/core/blockchain/serialization/BlockSerializerTest.java

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,23 @@
1616

1717
package com.exonum.binding.core.blockchain.serialization;
1818

19+
import static com.exonum.binding.core.blockchain.serialization.BlockSerializer.toHeadersMap;
20+
import static com.exonum.binding.core.blockchain.serialization.BlockSerializer.toHeadersProto;
1921
import static org.hamcrest.CoreMatchers.equalTo;
22+
import static org.hamcrest.CoreMatchers.is;
2023
import static org.hamcrest.MatcherAssert.assertThat;
2124

2225
import com.exonum.binding.common.hash.HashCode;
2326
import com.exonum.binding.common.serialization.Serializer;
2427
import com.exonum.binding.core.blockchain.Block;
2528
import com.exonum.binding.core.blockchain.Blocks;
29+
import com.exonum.core.messages.Blockchain.AdditionalHeaders;
30+
import com.exonum.core.messages.KeyValueSequenceOuterClass.KeyValue;
31+
import com.exonum.core.messages.KeyValueSequenceOuterClass.KeyValueSequence;
32+
import com.google.common.collect.ImmutableMap;
33+
import com.google.protobuf.ByteString;
2634
import java.util.stream.Stream;
35+
import org.junit.jupiter.api.Test;
2736
import org.junit.jupiter.params.ParameterizedTest;
2837
import org.junit.jupiter.params.provider.MethodSource;
2938

@@ -49,6 +58,8 @@ private static Stream<Block> testSource() {
4958
.previousBlockHash(HashCode.fromString("bc"))
5059
.txRootHash(HashCode.fromString("cd"))
5160
.stateHash(HashCode.fromString("ab"))
61+
.additionalHeaders(ImmutableMap.of())
62+
.errorHash(HashCode.fromString("ef"))
5263
.build();
5364
Block block2 = Block.builder()
5465
.proposerId(Integer.MAX_VALUE)
@@ -58,9 +69,34 @@ private static Stream<Block> testSource() {
5869
.previousBlockHash(HashCode.fromString("bc"))
5970
.txRootHash(HashCode.fromString("cd"))
6071
.stateHash(HashCode.fromString("ab"))
72+
.additionalHeaders(ImmutableMap.of("one", ByteString.copyFromUtf8("abcd01")))
73+
.errorHash(HashCode.fromString("ef"))
6174
.build();
6275

6376
return Stream.of(block1, block2)
6477
.map(Blocks::withProperHash);
6578
}
79+
80+
@Test
81+
void headersMapStrictOrderRoundTripTest() {
82+
KeyValue first = KeyValue.newBuilder()
83+
.setKey("foo")
84+
.setValue(ByteString.EMPTY)
85+
.build();
86+
KeyValue second = KeyValue.newBuilder()
87+
.setKey("bar")
88+
.setValue(ByteString.EMPTY)
89+
.build();
90+
AdditionalHeaders expected = AdditionalHeaders.newBuilder()
91+
.setHeaders(KeyValueSequence.newBuilder()
92+
.addEntry(first)
93+
.addEntry(second)
94+
.build())
95+
.build();
96+
97+
AdditionalHeaders actual = toHeadersProto(toHeadersMap(expected));
98+
99+
assertThat(actual, is(expected));
100+
}
101+
66102
}

0 commit comments

Comments
 (0)