Close #1142
Showing 10 of 11 files from the diff.
Libplanet.Tests/TestUtils.cs
changed.
Newly tracked file
...net/Blocks/InvalidBlockProtocolVersionException.cs
created.
Libplanet/Blockchain/BlockChain.cs
changed.
Libplanet/Blocks/BlockHeader.cs
changed.
Libplanet/Blocks/Block.cs
changed.
Other files ignored by Codecov
CHANGES.md
has changed.
@@ -179,7 +179,8 @@
Loading
179 | 179 | public static Block<T> MineGenesis<T>( |
|
180 | 180 | Address? miner = null, |
|
181 | 181 | IEnumerable<Transaction<T>> transactions = null, |
|
182 | - | DateTimeOffset? timestamp = null |
|
182 | + | DateTimeOffset? timestamp = null, |
|
183 | + | int protocolVersion = Block<T>.CurrentProtocolVersion |
|
183 | 184 | ) |
|
184 | 185 | where T : IAction, new() |
|
185 | 186 | { |
@@ -196,7 +197,8 @@
Loading
196 | 197 | miner: miner ?? GenesisMinerAddress, |
|
197 | 198 | previousHash: null, |
|
198 | 199 | timestamp: timestamp ?? new DateTimeOffset(2018, 11, 29, 0, 0, 0, TimeSpan.Zero), |
|
199 | - | transactions: transactions |
|
200 | + | transactions: transactions, |
|
201 | + | protocolVersion: protocolVersion |
|
200 | 202 | ); |
|
201 | 203 | ||
202 | 204 | return block; |
@@ -208,7 +210,8 @@
Loading
208 | 210 | byte[] nonce = null, |
|
209 | 211 | long difficulty = 1, |
|
210 | 212 | Address? miner = null, |
|
211 | - | TimeSpan? blockInterval = null |
|
213 | + | TimeSpan? blockInterval = null, |
|
214 | + | int protocolVersion = Block<T>.CurrentProtocolVersion |
|
212 | 215 | ) |
|
213 | 216 | where T : IAction, new() |
|
214 | 217 | { |
@@ -232,7 +235,8 @@
Loading
232 | 235 | miner: miner ?? previousBlock.Miner.Value, |
|
233 | 236 | previousHash: previousHash, |
|
234 | 237 | timestamp: timestamp, |
|
235 | - | transactions: txs |
|
238 | + | transactions: txs, |
|
239 | + | protocolVersion: protocolVersion |
|
236 | 240 | ); |
|
237 | 241 | } |
|
238 | 242 | else |
@@ -245,7 +249,8 @@
Loading
245 | 249 | miner: miner ?? previousBlock.Miner.Value, |
|
246 | 250 | previousHash: previousHash, |
|
247 | 251 | timestamp: timestamp, |
|
248 | - | transactions: txs |
|
252 | + | transactions: txs, |
|
253 | + | protocolVersion: protocolVersion |
|
249 | 254 | ); |
|
250 | 255 | } |
|
251 | 256 |
@@ -312,7 +317,8 @@
Loading
312 | 317 | PrivateKey privateKey = null, |
|
313 | 318 | DateTimeOffset? timestamp = null, |
|
314 | 319 | IEnumerable<IRenderer<T>> renderers = null, |
|
315 | - | Block<T> genesisBlock = null |
|
320 | + | Block<T> genesisBlock = null, |
|
321 | + | int protocolVersion = Block<T>.CurrentProtocolVersion |
|
316 | 322 | ) |
|
317 | 323 | where T : IAction, new() |
|
318 | 324 | { |
@@ -341,7 +347,9 @@
Loading
341 | 347 | GenesisMinerAddress, |
|
342 | 348 | null, |
|
343 | 349 | timestamp ?? DateTimeOffset.MinValue, |
|
344 | - | new[] { tx, }); |
|
350 | + | new[] { tx }, |
|
351 | + | protocolVersion: protocolVersion |
|
352 | + | ); |
|
345 | 353 | genesisBlock = genesisBlock.AttachStateRootHash(stateStore, policy.BlockAction); |
|
346 | 354 | ValidatingActionRenderer<T> validator = null; |
|
347 | 355 | #pragma warning disable S1121 |
@@ -0,0 +1,49 @@
Loading
1 | + | #nullable enable |
|
2 | + | using System; |
|
3 | + | using System.Runtime.Serialization; |
|
4 | + | ||
5 | + | namespace Libplanet.Blocks |
|
6 | + | { |
|
7 | + | /// <summary> |
|
8 | + | /// The exception that is thrown when a <see cref="Block{T}"/>'s |
|
9 | + | /// <see cref="Block{T}.ProtocolVersion"/> (or a <see cref="BlockHeader"/>'s |
|
10 | + | /// <see cref="BlockHeader.ProtocolVersion"/>) is invalid. |
|
11 | + | /// </summary> |
|
12 | + | [Serializable] |
|
13 | + | public sealed class InvalidBlockProtocolVersionException : InvalidBlockException, ISerializable |
|
14 | + | { |
|
15 | + | /// <summary> |
|
16 | + | /// Initializes a new instance of <see cref="InvalidBlockProtocolVersionException"/> class. |
|
17 | + | /// </summary> |
|
18 | + | /// <param name="actualProtocolVersion">The actual block protocol version which is invalid. |
|
19 | + | /// </param> |
|
20 | + | /// <param name="message">The message that describes the error.</param> |
|
21 | + | public InvalidBlockProtocolVersionException(int actualProtocolVersion, string message) |
|
22 | + | : base(message) |
|
23 | + | { |
|
24 | + | ActualProtocolVersion = actualProtocolVersion; |
|
25 | + | } |
|
26 | + | ||
27 | + | private InvalidBlockProtocolVersionException( |
|
28 | + | SerializationInfo info, |
|
29 | + | StreamingContext context |
|
30 | + | ) |
|
31 | + | : base(info.GetString(nameof(Message)) ?? string.Empty) |
|
32 | + | { |
|
33 | + | ActualProtocolVersion = info.GetInt32(nameof(ActualProtocolVersion)); |
|
34 | + | } |
|
35 | + | ||
36 | + | /// <summary> |
|
37 | + | /// The actual block protocol version which is invalid. |
|
38 | + | /// </summary> |
|
39 | + | public int ActualProtocolVersion { get; set; } |
|
40 | + | ||
41 | + | /// <inheritdoc cref="Exception.GetObjectData(SerializationInfo, StreamingContext)"/> |
|
42 | + | public override void GetObjectData(SerializationInfo info, StreamingContext context) |
|
43 | + | { |
|
44 | + | base.GetObjectData(info, context); |
|
45 | + | info.AddValue(nameof(Message), Message); |
|
46 | + | info.AddValue(nameof(ActualProtocolVersion), ActualProtocolVersion); |
|
47 | + | } |
|
48 | + | } |
|
49 | + | } |
@@ -1935,6 +1935,27 @@
Loading
1935 | 1935 | ||
1936 | 1936 | private InvalidBlockException ValidateNextBlock(Block<T> nextBlock) |
|
1937 | 1937 | { |
|
1938 | + | int actualProtocolVersion = nextBlock.ProtocolVersion; |
|
1939 | + | const int currentProtocolVersion = Block<T>.CurrentProtocolVersion; |
|
1940 | + | if (actualProtocolVersion > currentProtocolVersion) |
|
1941 | + | { |
|
1942 | + | string message = |
|
1943 | + | $"The protocol version ({actualProtocolVersion}) of the block " + |
|
1944 | + | $"#{nextBlock.Index} {nextBlock.Hash} is not supported by this node." + |
|
1945 | + | $"The highest supported protocol version is {currentProtocolVersion}."; |
|
1946 | + | throw new InvalidBlockProtocolVersionException( |
|
1947 | + | actualProtocolVersion, |
|
1948 | + | message |
|
1949 | + | ); |
|
1950 | + | } |
|
1951 | + | else if (Tip is { } tip && actualProtocolVersion < tip.ProtocolVersion) |
|
1952 | + | { |
|
1953 | + | string message = |
|
1954 | + | "The protocol version is disallowed to be downgraded from the topmost block " + |
|
1955 | + | $"in the chain ({actualProtocolVersion} < {tip.ProtocolVersion})."; |
|
1956 | + | throw new InvalidBlockProtocolVersionException(actualProtocolVersion, message); |
|
1957 | + | } |
|
1958 | + | ||
1938 | 1959 | InvalidBlockException e = Policy.ValidateNextBlock(this, nextBlock); |
|
1939 | 1960 | ||
1940 | 1961 | if (!(e is null)) |
@@ -9,13 +9,19 @@
Loading
9 | 9 | { |
|
10 | 10 | public class BlockFixture |
|
11 | 11 | { |
|
12 | + | public const int ProtocolVersion = |
|
13 | + | Block<PolymorphicAction<BaseAction>>.CurrentProtocolVersion; |
|
14 | + | ||
12 | 15 | public BlockFixture() |
|
13 | 16 | { |
|
14 | - | Genesis = TestUtils.MineGenesis<PolymorphicAction<BaseAction>>(); |
|
17 | + | Genesis = TestUtils.MineGenesis<PolymorphicAction<BaseAction>>( |
|
18 | + | protocolVersion: ProtocolVersion |
|
19 | + | ); |
|
15 | 20 | TxFixture = new TxFixture(Genesis.Hash); |
|
16 | 21 | Next = TestUtils.MineNext( |
|
17 | 22 | Genesis, |
|
18 | - | nonce: new byte[] { 0x02, 0x00, 0x00, 0x00 } |
|
23 | + | nonce: new byte[] { 0x02, 0x00, 0x00, 0x00 }, |
|
24 | + | protocolVersion: ProtocolVersion |
|
19 | 25 | ); |
|
20 | 26 | byte[] hasTxNonce = |
|
21 | 27 | { |
@@ -27,7 +33,8 @@
Loading
27 | 33 | { |
|
28 | 34 | TxFixture.TxWithActions, |
|
29 | 35 | }, |
|
30 | - | hasTxNonce |
|
36 | + | hasTxNonce, |
|
37 | + | protocolVersion: ProtocolVersion |
|
31 | 38 | ); |
|
32 | 39 | } |
|
33 | 40 |
@@ -16,18 +16,59 @@
Loading
16 | 16 | [Fact] |
|
17 | 17 | public void ValidateNextBlock() |
|
18 | 18 | { |
|
19 | - | var validNextBlock = Block<DumbAction>.Mine( |
|
19 | + | Block<DumbAction> validNextBlock = Block<DumbAction>.Mine( |
|
20 | 20 | 1, |
|
21 | 21 | 1024, |
|
22 | 22 | _fx.GenesisBlock.TotalDifficulty, |
|
23 | 23 | _fx.GenesisBlock.Miner.Value, |
|
24 | 24 | _fx.GenesisBlock.Hash, |
|
25 | 25 | _fx.GenesisBlock.Timestamp.AddDays(1), |
|
26 | - | _emptyTransaction).AttachStateRootHash(_fx.StateStore, _policy.BlockAction); |
|
26 | + | _emptyTransaction |
|
27 | + | ).AttachStateRootHash(_fx.StateStore, _policy.BlockAction); |
|
27 | 28 | _blockChain.Append(validNextBlock); |
|
28 | 29 | Assert.Equal(_blockChain.Tip, validNextBlock); |
|
29 | 30 | } |
|
30 | 31 | ||
32 | + | [Fact] |
|
33 | + | private void ValidateNextBlockProtocolVersion() |
|
34 | + | { |
|
35 | + | Block<DumbAction> block1 = Block<DumbAction>.Mine( |
|
36 | + | 1, |
|
37 | + | 1024, |
|
38 | + | _fx.GenesisBlock.TotalDifficulty, |
|
39 | + | _fx.GenesisBlock.Miner.Value, |
|
40 | + | _fx.GenesisBlock.Hash, |
|
41 | + | _fx.GenesisBlock.Timestamp.AddDays(1), |
|
42 | + | _emptyTransaction, |
|
43 | + | protocolVersion: 1 |
|
44 | + | ).AttachStateRootHash(_fx.StateStore, _policy.BlockAction); |
|
45 | + | _blockChain.Append(block1); |
|
46 | + | ||
47 | + | Block<DumbAction> block2 = Block<DumbAction>.Mine( |
|
48 | + | 2, |
|
49 | + | 1024, |
|
50 | + | block1.TotalDifficulty, |
|
51 | + | _fx.GenesisBlock.Miner.Value, |
|
52 | + | block1.Hash, |
|
53 | + | _fx.GenesisBlock.Timestamp.AddDays(1), |
|
54 | + | _emptyTransaction, |
|
55 | + | protocolVersion: 0 |
|
56 | + | ).AttachStateRootHash(_fx.StateStore, _policy.BlockAction); |
|
57 | + | Assert.Throws<InvalidBlockProtocolVersionException>(() => _blockChain.Append(block2)); |
|
58 | + | ||
59 | + | Block<DumbAction> block3 = Block<DumbAction>.Mine( |
|
60 | + | 2, |
|
61 | + | 1024, |
|
62 | + | block1.TotalDifficulty, |
|
63 | + | _fx.GenesisBlock.Miner.Value, |
|
64 | + | block1.Hash, |
|
65 | + | _fx.GenesisBlock.Timestamp.AddDays(1), |
|
66 | + | _emptyTransaction, |
|
67 | + | protocolVersion: Block<DumbAction>.CurrentProtocolVersion + 1 |
|
68 | + | ).AttachStateRootHash(_fx.StateStore, _policy.BlockAction); |
|
69 | + | Assert.Throws<InvalidBlockProtocolVersionException>(() => _blockChain.Append(block3)); |
|
70 | + | } |
|
71 | + | ||
31 | 72 | [Fact] |
|
32 | 73 | private void ValidateNextBlockInvalidIndex() |
|
33 | 74 | { |
@@ -1,6 +1,8 @@
Loading
1 | 1 | using System; |
|
2 | 2 | using System.Collections.Immutable; |
|
3 | 3 | using System.Globalization; |
|
4 | + | using System.Linq; |
|
5 | + | using Bencodex.Types; |
|
4 | 6 | using Libplanet.Blocks; |
|
5 | 7 | using Xunit; |
|
6 | 8 |
@@ -12,6 +14,123 @@
Loading
12 | 14 | ||
13 | 15 | public BlockHeaderTest(BlockFixture fixture) => _fx = fixture; |
|
14 | 16 | ||
17 | + | [Fact] |
|
18 | + | public void ToBencodex() |
|
19 | + | { |
|
20 | + | var header = new BlockHeader( |
|
21 | + | protocolVersion: 0, |
|
22 | + | index: 0, |
|
23 | + | difficulty: _fx.Genesis.Difficulty, |
|
24 | + | totalDifficulty: _fx.Genesis.TotalDifficulty, |
|
25 | + | nonce: _fx.Genesis.Nonce.ByteArray, |
|
26 | + | miner: _fx.Genesis.Miner?.ByteArray ?? ImmutableArray<byte>.Empty, |
|
27 | + | hash: _fx.Genesis.Hash.ByteArray, |
|
28 | + | txHash: _fx.Genesis.TxHash?.ByteArray ?? ImmutableArray<byte>.Empty, |
|
29 | + | previousHash: _fx.Genesis.PreviousHash?.ByteArray ?? ImmutableArray<byte>.Empty, |
|
30 | + | timestamp: _fx.Genesis.Timestamp.ToString( |
|
31 | + | BlockHeader.TimestampFormat, |
|
32 | + | CultureInfo.InvariantCulture |
|
33 | + | ), |
|
34 | + | preEvaluationHash: _fx.Genesis.PreEvaluationHash.ByteArray, |
|
35 | + | stateRootHash: _fx.Genesis.StateRootHash?.ByteArray ?? ImmutableArray<byte>.Empty |
|
36 | + | ); |
|
37 | + | Bencodex.Types.Dictionary expected = Bencodex.Types.Dictionary.Empty |
|
38 | + | .Add(BlockHeader.IndexKey, 0) |
|
39 | + | .Add( |
|
40 | + | BlockHeader.TimestampKey, |
|
41 | + | _fx.Genesis.Timestamp.ToString( |
|
42 | + | BlockHeader.TimestampFormat, |
|
43 | + | CultureInfo.InvariantCulture |
|
44 | + | ) |
|
45 | + | ) |
|
46 | + | .Add(BlockHeader.DifficultyKey, _fx.Genesis.Difficulty) |
|
47 | + | .Add( |
|
48 | + | BlockHeader.TotalDifficultyKey, |
|
49 | + | (IValue)new Bencodex.Types.Integer(_fx.Genesis.TotalDifficulty) |
|
50 | + | ) |
|
51 | + | .Add(BlockHeader.NonceKey, _fx.Genesis.Nonce.ToByteArray()) |
|
52 | + | .Add(BlockHeader.HashKey, _fx.Genesis.Hash.ToByteArray()) |
|
53 | + | .Add(BlockHeader.MinerKey, _fx.Genesis.Miner?.ToByteArray() ?? new byte[0]) |
|
54 | + | .Add(BlockHeader.PreEvaluationHashKey, _fx.Genesis.PreEvaluationHash.ToByteArray()); |
|
55 | + | Assert.Equal(expected, header.ToBencodex()); |
|
56 | + | Assert.Equal(expected, new BlockHeader(expected).ToBencodex()); |
|
57 | + | ||
58 | + | ImmutableArray<byte> randomHash = TestUtils.GetRandomBytes(32).ToImmutableArray(); |
|
59 | + | ImmutableArray<byte> randomHash2 = TestUtils.GetRandomBytes(32).ToImmutableArray(); |
|
60 | + | header = new BlockHeader( |
|
61 | + | protocolVersion: 1, |
|
62 | + | index: 1, |
|
63 | + | difficulty: _fx.Next.Difficulty, |
|
64 | + | totalDifficulty: _fx.Next.TotalDifficulty, |
|
65 | + | nonce: _fx.Next.Nonce.ByteArray, |
|
66 | + | miner: ImmutableArray<byte>.Empty, |
|
67 | + | hash: _fx.Next.Hash.ByteArray, |
|
68 | + | txHash: randomHash, |
|
69 | + | previousHash: _fx.Genesis.Hash.ByteArray, |
|
70 | + | timestamp: _fx.Next.Timestamp.ToString( |
|
71 | + | BlockHeader.TimestampFormat, |
|
72 | + | CultureInfo.InvariantCulture |
|
73 | + | ), |
|
74 | + | preEvaluationHash: ImmutableArray<byte>.Empty, |
|
75 | + | stateRootHash: randomHash2 |
|
76 | + | ); |
|
77 | + | expected = Bencodex.Types.Dictionary.Empty |
|
78 | + | .Add(BlockHeader.ProtocolVersionKey, 1) |
|
79 | + | .Add(BlockHeader.IndexKey, 1) |
|
80 | + | .Add( |
|
81 | + | BlockHeader.TimestampKey, |
|
82 | + | _fx.Next.Timestamp.ToString( |
|
83 | + | BlockHeader.TimestampFormat, |
|
84 | + | CultureInfo.InvariantCulture |
|
85 | + | ) |
|
86 | + | ) |
|
87 | + | .Add(BlockHeader.DifficultyKey, _fx.Next.Difficulty) |
|
88 | + | .Add( |
|
89 | + | BlockHeader.TotalDifficultyKey, |
|
90 | + | (IValue)new Bencodex.Types.Integer(_fx.Next.TotalDifficulty) |
|
91 | + | ) |
|
92 | + | .Add(BlockHeader.NonceKey, _fx.Next.Nonce.ToByteArray()) |
|
93 | + | .Add(BlockHeader.HashKey, _fx.Next.Hash.ToByteArray()) |
|
94 | + | .Add(BlockHeader.PreviousHashKey, _fx.Genesis.Hash.ToByteArray()) |
|
95 | + | .Add(BlockHeader.TxHashKey, randomHash.ToArray()) |
|
96 | + | .Add(BlockHeader.StateRootHashKey, randomHash2.ToArray()); |
|
97 | + | Assert.Equal(expected, header.ToBencodex()); |
|
98 | + | Assert.Equal(expected, new BlockHeader(expected).ToBencodex()); |
|
99 | + | } |
|
100 | + | ||
101 | + | [Fact] |
|
102 | + | public void ValidateValidHeader() |
|
103 | + | { |
|
104 | + | _fx.Genesis.Header.Validate(DateTimeOffset.UtcNow); |
|
105 | + | _fx.Next.Header.Validate(DateTimeOffset.UtcNow); |
|
106 | + | } |
|
107 | + | ||
108 | + | [Fact] |
|
109 | + | public void ValidateProtocolVersion() |
|
110 | + | { |
|
111 | + | var header = new BlockHeader( |
|
112 | + | protocolVersion: -1, |
|
113 | + | index: 0, |
|
114 | + | difficulty: _fx.Next.Difficulty, |
|
115 | + | totalDifficulty: _fx.Next.TotalDifficulty, |
|
116 | + | nonce: _fx.Next.Nonce.ByteArray, |
|
117 | + | miner: _fx.Next.Miner?.ByteArray ?? ImmutableArray<byte>.Empty, |
|
118 | + | hash: _fx.Next.Hash.ByteArray, |
|
119 | + | txHash: _fx.Next.TxHash?.ByteArray ?? ImmutableArray<byte>.Empty, |
|
120 | + | previousHash: _fx.Next.PreviousHash?.ByteArray ?? ImmutableArray<byte>.Empty, |
|
121 | + | timestamp: _fx.Next.Timestamp.ToString( |
|
122 | + | BlockHeader.TimestampFormat, |
|
123 | + | CultureInfo.InvariantCulture |
|
124 | + | ), |
|
125 | + | preEvaluationHash: TestUtils.GetRandomBytes(32).ToImmutableArray(), |
|
126 | + | stateRootHash: ImmutableArray<byte>.Empty |
|
127 | + | ); |
|
128 | + | ||
129 | + | Assert.Throws<InvalidBlockProtocolVersionException>(() => |
|
130 | + | header.Validate(DateTimeOffset.UtcNow) |
|
131 | + | ); |
|
132 | + | } |
|
133 | + | ||
15 | 134 | [Fact] |
|
16 | 135 | public void ValidateTimestamp() |
|
17 | 136 | { |
@@ -19,6 +138,7 @@
Loading
19 | 138 | string future = (now + TimeSpan.FromSeconds(16)) |
|
20 | 139 | .ToString(BlockHeader.TimestampFormat, CultureInfo.InvariantCulture); |
|
21 | 140 | var header = new BlockHeader( |
|
141 | + | protocolVersion: 0, |
|
22 | 142 | index: 0, |
|
23 | 143 | difficulty: 0, |
|
24 | 144 | totalDifficulty: 0, |
@@ -43,6 +163,7 @@
Loading
43 | 163 | public void ValidateNonce() |
|
44 | 164 | { |
|
45 | 165 | var header = new BlockHeader( |
|
166 | + | protocolVersion: 0, |
|
46 | 167 | index: _fx.Next.Index, |
|
47 | 168 | difficulty: long.MaxValue, |
|
48 | 169 | totalDifficulty: _fx.Genesis.TotalDifficulty + long.MaxValue, |
@@ -67,6 +188,7 @@
Loading
67 | 188 | public void ValidateIndex() |
|
68 | 189 | { |
|
69 | 190 | var header = new BlockHeader( |
|
191 | + | protocolVersion: 0, |
|
70 | 192 | index: -1, |
|
71 | 193 | difficulty: _fx.Next.Difficulty, |
|
72 | 194 | totalDifficulty: _fx.Next.TotalDifficulty, |
@@ -92,6 +214,7 @@
Loading
92 | 214 | { |
|
93 | 215 | DateTimeOffset now = DateTimeOffset.UtcNow; |
|
94 | 216 | var genesisHeader = new BlockHeader( |
|
217 | + | protocolVersion: 0, |
|
95 | 218 | index: 0, |
|
96 | 219 | difficulty: 1000, |
|
97 | 220 | totalDifficulty: 1000, |
@@ -109,6 +232,7 @@
Loading
109 | 232 | genesisHeader.Validate(DateTimeOffset.UtcNow)); |
|
110 | 233 | ||
111 | 234 | var header1 = new BlockHeader( |
|
235 | + | protocolVersion: 0, |
|
112 | 236 | index: 10, |
|
113 | 237 | difficulty: 0, |
|
114 | 238 | totalDifficulty: 1000, |
@@ -126,6 +250,7 @@
Loading
126 | 250 | header1.Validate(DateTimeOffset.UtcNow)); |
|
127 | 251 | ||
128 | 252 | var header2 = new BlockHeader( |
|
253 | + | protocolVersion: 0, |
|
129 | 254 | index: 10, |
|
130 | 255 | difficulty: 1000, |
|
131 | 256 | totalDifficulty: 10, |
@@ -148,6 +273,7 @@
Loading
148 | 273 | { |
|
149 | 274 | DateTimeOffset now = DateTimeOffset.UtcNow; |
|
150 | 275 | var genesisHeader = new BlockHeader( |
|
276 | + | protocolVersion: 0, |
|
151 | 277 | index: 0, |
|
152 | 278 | difficulty: 0, |
|
153 | 279 | totalDifficulty: 0, |
@@ -165,6 +291,7 @@
Loading
165 | 291 | genesisHeader.Validate(DateTimeOffset.UtcNow)); |
|
166 | 292 | ||
167 | 293 | var header = new BlockHeader( |
|
294 | + | protocolVersion: 0, |
|
168 | 295 | index: 10, |
|
169 | 296 | difficulty: 1000, |
|
170 | 297 | totalDifficulty: 1500, |
@@ -73,7 +73,7 @@
Loading
73 | 73 | } |
|
74 | 74 | ||
75 | 75 | [Fact] |
|
76 | - | public void CanMine() |
|
76 | + | public void Mine() |
|
77 | 77 | { |
|
78 | 78 | Assert.Equal(0, _fx.Genesis.Index); |
|
79 | 79 | Assert.Equal(0, _fx.Genesis.Difficulty); |
@@ -90,9 +90,9 @@
Loading
90 | 90 | new HashDigest<SHA256>( |
|
91 | 91 | new byte[] |
|
92 | 92 | { |
|
93 | - | 0xd4, 0xf3, 0x58, 0x34, 0xe2, 0x7d, 0x5a, 0xb4, 0x59, 0xa4, 0xd4, 0x01, |
|
94 | - | 0xe9, 0xa0, 0x82, 0x68, 0xe3, 0xfe, 0x32, 0x1b, 0x8c, 0x68, 0x50, 0x75, |
|
95 | - | 0xae, 0xc5, 0xbd, 0x5d, 0x18, 0xd6, 0x42, 0xaa, |
|
93 | + | 0xd6, 0x93, 0xda, 0x38, 0x66, 0xa3, 0x4d, 0x65, 0x9e, 0x01, 0x4f, 0x97, |
|
94 | + | 0xc8, 0xfe, 0xb0, 0x8a, 0xfe, 0x2e, 0x97, 0xc9, 0x9e, 0x3f, 0x33, 0x89, |
|
95 | + | 0xda, 0x02, 0x5f, 0xd0, 0x66, 0x5c, 0x62, 0x1c, |
|
96 | 96 | } |
|
97 | 97 | ), |
|
98 | 98 | _fx.Genesis.Hash |
@@ -117,20 +117,19 @@
Loading
117 | 117 | { |
|
118 | 118 | byte[] expected = |
|
119 | 119 | { |
|
120 | - | 0x64, 0x31, 0x3a, 0x48, 0x64, 0x31, 0x3a, 0x54, 0x69, 0x30, 0x65, 0x31, 0x3a, |
|
121 | - | 0x63, 0x33, 0x32, 0x3a, 0xd4, 0xf3, 0x58, 0x34, 0xe2, 0x7d, 0x5a, 0xb4, 0x59, |
|
122 | - | 0xa4, 0xd4, 0x01, 0xe9, 0xa0, 0x82, 0x68, 0xe3, 0xfe, 0x32, 0x1b, 0x8c, 0x68, |
|
123 | - | 0x50, 0x75, 0xae, 0xc5, 0xbd, 0x5d, 0x18, 0xd6, 0x42, 0xaa, 0x31, 0x3a, 0x64, |
|
124 | - | 0x69, 0x30, 0x65, 0x31, 0x3a, 0x68, 0x33, 0x32, 0x3a, 0xd4, 0xf3, 0x58, 0x34, |
|
125 | - | 0xe2, 0x7d, 0x5a, 0xb4, 0x59, 0xa4, 0xd4, 0x01, 0xe9, 0xa0, 0x82, 0x68, 0xe3, |
|
126 | - | 0xfe, 0x32, 0x1b, 0x8c, 0x68, 0x50, 0x75, 0xae, 0xc5, 0xbd, 0x5d, 0x18, 0xd6, |
|
127 | - | 0x42, 0xaa, 0x31, 0x3a, 0x69, 0x69, 0x30, 0x65, 0x31, 0x3a, 0x6d, 0x32, 0x30, |
|
128 | - | 0x3a, 0x21, 0x74, 0x4f, 0x4f, 0x08, 0xdb, 0x23, 0xe0, 0x44, 0x17, 0x8d, 0xaf, |
|
129 | - | 0xb8, 0x27, 0x3a, 0xeb, 0x5e, 0xbe, 0x66, 0x44, 0x31, 0x3a, 0x6e, 0x34, 0x3a, |
|
130 | - | 0x01, 0x00, 0x00, 0x00, 0x31, 0x3a, 0x74, 0x75, 0x32, 0x37, 0x3a, 0x32, 0x30, |
|
131 | - | 0x31, 0x38, 0x2d, 0x31, 0x31, 0x2d, 0x32, 0x39, 0x54, 0x30, 0x30, 0x3a, 0x30, |
|
132 | - | 0x30, 0x3a, 0x30, 0x30, 0x2e, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x65, |
|
133 | - | 0x65, |
|
120 | + | 0x64, 0x31, 0x3a, 0x48, 0x64, 0x31, 0x3a, 0x00, 0x69, 0x31, 0x65, 0x31, 0x3a, 0x54, |
|
121 | + | 0x69, 0x30, 0x65, 0x31, 0x3a, 0x63, 0x33, 0x32, 0x3a, 0xd6, 0x93, 0xda, 0x38, 0x66, |
|
122 | + | 0xa3, 0x4d, 0x65, 0x9e, 0x01, 0x4f, 0x97, 0xc8, 0xfe, 0xb0, 0x8a, 0xfe, 0x2e, 0x97, |
|
123 | + | 0xc9, 0x9e, 0x3f, 0x33, 0x89, 0xda, 0x02, 0x5f, 0xd0, 0x66, 0x5c, 0x62, 0x1c, 0x31, |
|
124 | + | 0x3a, 0x64, 0x69, 0x30, 0x65, 0x31, 0x3a, 0x68, 0x33, 0x32, 0x3a, 0xd6, 0x93, 0xda, |
|
125 | + | 0x38, 0x66, 0xa3, 0x4d, 0x65, 0x9e, 0x01, 0x4f, 0x97, 0xc8, 0xfe, 0xb0, 0x8a, 0xfe, |
|
126 | + | 0x2e, 0x97, 0xc9, 0x9e, 0x3f, 0x33, 0x89, 0xda, 0x02, 0x5f, 0xd0, 0x66, 0x5c, 0x62, |
|
127 | + | 0x1c, 0x31, 0x3a, 0x69, 0x69, 0x30, 0x65, 0x31, 0x3a, 0x6d, 0x32, 0x30, 0x3a, 0x21, |
|
128 | + | 0x74, 0x4f, 0x4f, 0x08, 0xdb, 0x23, 0xe0, 0x44, 0x17, 0x8d, 0xaf, 0xb8, 0x27, 0x3a, |
|
129 | + | 0xeb, 0x5e, 0xbe, 0x66, 0x44, 0x31, 0x3a, 0x6e, 0x34, 0x3a, 0x01, 0x00, 0x00, 0x00, |
|
130 | + | 0x31, 0x3a, 0x74, 0x75, 0x32, 0x37, 0x3a, 0x32, 0x30, 0x31, 0x38, 0x2d, 0x31, 0x31, |
|
131 | + | 0x2d, 0x32, 0x39, 0x54, 0x30, 0x30, 0x3a, 0x30, 0x30, 0x3a, 0x30, 0x30, 0x2e, 0x30, |
|
132 | + | 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x65, 0x65, |
|
134 | 133 | }; |
|
135 | 134 | ||
136 | 135 | AssertBytesEqual(expected, _fx.Genesis.Serialize()); |
@@ -142,56 +141,57 @@
Loading
142 | 141 | { |
|
143 | 142 | byte[] encoded = |
|
144 | 143 | { |
|
145 | - | 0x64, 0x31, 0x3a, 0x48, 0x64, 0x31, 0x3a, 0x54, 0x69, 0x32, 0x65, 0x31, 0x3a, 0x63, |
|
146 | - | 0x33, 0x32, 0x3a, 0x22, 0xe1, 0x3b, 0xb5, 0x46, 0x65, 0x91, 0x34, 0x28, 0xbc, 0x55, |
|
147 | - | 0x86, 0xce, 0xbd, 0x50, 0xdc, 0x25, 0x50, 0xb0, 0x36, 0xa6, 0x18, 0xe9, 0xb0, 0x5d, |
|
148 | - | 0xb1, 0x1c, 0x76, 0xad, 0xb0, 0x0a, 0xd7, 0x31, 0x3a, 0x64, 0x69, 0x31, 0x65, 0x31, |
|
149 | - | 0x3a, 0x68, 0x33, 0x32, 0x3a, 0x22, 0xe1, 0x3b, 0xb5, 0x46, 0x65, 0x91, 0x34, 0x28, |
|
150 | - | 0xbc, 0x55, 0x86, 0xce, 0xbd, 0x50, 0xdc, 0x25, 0x50, 0xb0, 0x36, 0xa6, 0x18, 0xe9, |
|
151 | - | 0xb0, 0x5d, 0xb1, 0x1c, 0x76, 0xad, 0xb0, 0x0a, 0xd7, 0x31, 0x3a, 0x69, 0x69, 0x32, |
|
152 | - | 0x65, 0x31, 0x3a, 0x6d, 0x32, 0x30, 0x3a, 0x21, 0x74, 0x4f, 0x4f, 0x08, 0xdb, 0x23, |
|
153 | - | 0xe0, 0x44, 0x17, 0x8d, 0xaf, 0xb8, 0x27, 0x3a, 0xeb, 0x5e, 0xbe, 0x66, 0x44, 0x31, |
|
154 | - | 0x3a, 0x6e, 0x31, 0x30, 0x3a, 0x5c, 0x77, 0x74, 0xc2, 0x39, 0x69, 0x37, 0x51, 0x87, |
|
155 | - | 0xa5, 0x31, 0x3a, 0x70, 0x33, 0x32, 0x3a, 0x1c, 0xd4, 0x45, 0x16, 0x24, 0xef, 0x9c, |
|
156 | - | 0x79, 0xe2, 0xc2, 0xfb, 0x5a, 0x8e, 0x79, 0x1e, 0x4f, 0xa5, 0x6a, 0x7d, 0x8c, 0x61, |
|
157 | - | 0x0c, 0x14, 0xa8, 0xa3, 0x4a, 0xe1, 0x75, 0xb5, 0x20, 0x5c, 0xf7, 0x31, 0x3a, 0x74, |
|
158 | - | 0x75, 0x32, 0x37, 0x3a, 0x32, 0x30, 0x31, 0x38, 0x2d, 0x31, 0x31, 0x2d, 0x32, 0x39, |
|
159 | - | 0x54, 0x30, 0x30, 0x3a, 0x30, 0x30, 0x3a, 0x33, 0x30, 0x2e, 0x30, 0x30, 0x30, 0x30, |
|
160 | - | 0x30, 0x30, 0x5a, 0x31, 0x3a, 0x78, 0x33, 0x32, 0x3a, 0x97, 0x3c, 0xa5, 0xff, 0xce, |
|
161 | - | 0x89, 0x84, 0xc0, 0x39, 0xe6, 0x3f, 0x2b, 0xee, 0x2f, 0x01, 0x67, 0x00, 0x51, 0x00, |
|
162 | - | 0xa0, 0xfb, 0xa4, 0x71, 0x4f, 0xf6, 0xfb, 0x67, 0xe0, 0xaf, 0x61, 0x53, 0x00, 0x65, |
|
163 | - | 0x31, 0x3a, 0x54, 0x6c, 0x34, 0x33, 0x35, 0x3a, 0x64, 0x31, 0x3a, 0x53, 0x37, 0x30, |
|
164 | - | 0x3a, 0x30, 0x44, 0x02, 0x20, 0x01, 0xb6, 0x10, 0xa7, 0x15, 0xda, 0x89, 0x15, 0x1b, |
|
165 | - | 0x5f, 0x62, 0xde, 0xea, 0x12, 0x92, 0xe4, 0x48, 0x80, 0xa3, 0x7d, 0x8a, 0xbe, 0x38, |
|
166 | - | 0xd3, 0x03, 0x73, 0x4f, 0x48, 0x91, 0xcd, 0xc9, 0x47, 0x02, 0x20, 0x50, 0x63, 0xb9, |
|
167 | - | 0x8f, 0xef, 0xc7, 0x6f, 0x54, 0x53, 0x2c, 0x94, 0x7d, 0x99, 0xc2, 0x0e, 0x1e, 0xd3, |
|
168 | - | 0xac, 0xd7, 0xc4, 0x57, 0xed, 0x18, 0x3d, 0x59, 0x02, 0xa8, 0x3a, 0x61, 0xfa, 0x68, |
|
169 | - | 0x8f, 0x31, 0x3a, 0x61, 0x6c, 0x64, 0x75, 0x37, 0x3a, 0x74, 0x79, 0x70, 0x65, 0x5f, |
|
170 | - | 0x69, 0x64, 0x75, 0x36, 0x3a, 0x61, 0x74, 0x74, 0x61, 0x63, 0x6b, 0x75, 0x36, 0x3a, |
|
171 | - | 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x64, 0x75, 0x36, 0x3a, 0x74, 0x61, 0x72, 0x67, |
|
172 | - | 0x65, 0x74, 0x75, 0x33, 0x3a, 0x6f, 0x72, 0x63, 0x75, 0x31, 0x34, 0x3a, 0x74, 0x61, |
|
173 | - | 0x72, 0x67, 0x65, 0x74, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x32, 0x30, |
|
174 | - | 0x3a, 0xc2, 0xa8, 0x60, 0x14, 0x07, 0x3d, 0x66, 0x2a, 0x4a, 0x9b, 0xfc, 0xf9, 0xcb, |
|
175 | - | 0x54, 0x26, 0x3d, 0xfa, 0x4f, 0x5c, 0xbc, 0x75, 0x36, 0x3a, 0x77, 0x65, 0x61, 0x70, |
|
176 | - | 0x6f, 0x6e, 0x75, 0x34, 0x3a, 0x77, 0x61, 0x6e, 0x64, 0x65, 0x65, 0x64, 0x75, 0x37, |
|
177 | - | 0x3a, 0x74, 0x79, 0x70, 0x65, 0x5f, 0x69, 0x64, 0x75, 0x35, 0x3a, 0x73, 0x6c, 0x65, |
|
178 | - | 0x65, 0x70, 0x75, 0x36, 0x3a, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x64, 0x75, 0x37, |
|
179 | - | 0x3a, 0x7a, 0x6f, 0x6e, 0x65, 0x5f, 0x69, 0x64, 0x69, 0x31, 0x30, 0x65, 0x65, 0x65, |
|
180 | - | 0x65, 0x31, 0x3a, 0x67, 0x33, 0x32, 0x3a, 0xd4, 0xf3, 0x58, 0x34, 0xe2, 0x7d, 0x5a, |
|
181 | - | 0xb4, 0x59, 0xa4, 0xd4, 0x01, 0xe9, 0xa0, 0x82, 0x68, 0xe3, 0xfe, 0x32, 0x1b, 0x8c, |
|
182 | - | 0x68, 0x50, 0x75, 0xae, 0xc5, 0xbd, 0x5d, 0x18, 0xd6, 0x42, 0xaa, 0x31, 0x3a, 0x6e, |
|
183 | - | 0x69, 0x30, 0x65, 0x31, 0x3a, 0x70, 0x36, 0x35, 0x3a, 0x04, 0x46, 0x11, 0x5b, 0x01, |
|
184 | - | 0x31, 0xba, 0xcc, 0xf9, 0x4a, 0x58, 0x56, 0xed, 0xe8, 0x71, 0x29, 0x5f, 0x6f, 0x3d, |
|
185 | - | 0x35, 0x2e, 0x68, 0x47, 0xcd, 0xa9, 0xc0, 0x3e, 0x89, 0xfe, 0x09, 0xf7, 0x32, 0x80, |
|
186 | - | 0x87, 0x11, 0xec, 0x97, 0xaf, 0x6e, 0x34, 0x1f, 0x11, 0x0a, 0x32, 0x6d, 0xa1, 0xbd, |
|
187 | - | 0xb8, 0x1f, 0x5a, 0xe3, 0xba, 0xdf, 0x76, 0xa9, 0x0b, 0x22, 0xc8, 0xc4, 0x91, 0xae, |
|
188 | - | 0xd3, 0xaa, 0xa2, 0x96, 0x31, 0x3a, 0x73, 0x32, 0x30, 0x3a, 0xc2, 0xa8, 0x60, 0x14, |
|
189 | - | 0x07, 0x3d, 0x66, 0x2a, 0x4a, 0x9b, 0xfc, 0xf9, 0xcb, 0x54, 0x26, 0x3d, 0xfa, 0x4f, |
|
190 | - | 0x5c, 0xbc, 0x31, 0x3a, 0x74, 0x75, 0x32, 0x37, 0x3a, 0x32, 0x30, 0x31, 0x38, 0x2d, |
|
191 | - | 0x31, 0x31, 0x2d, 0x32, 0x31, 0x54, 0x30, 0x30, 0x3a, 0x30, 0x30, 0x3a, 0x30, 0x30, |
|
192 | - | 0x2e, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x31, 0x3a, 0x75, 0x6c, 0x32, 0x30, |
|
193 | - | 0x3a, 0xc2, 0xa8, 0x60, 0x14, 0x07, 0x3d, 0x66, 0x2a, 0x4a, 0x9b, 0xfc, 0xf9, 0xcb, |
|
194 | - | 0x54, 0x26, 0x3d, 0xfa, 0x4f, 0x5c, 0xbc, 0x65, 0x65, 0x65, 0x65, |
|
144 | + | 0x64, 0x31, 0x3a, 0x48, 0x64, 0x31, 0x3a, 0x00, 0x69, 0x31, 0x65, 0x31, 0x3a, 0x54, |
|
145 | + | 0x69, 0x32, 0x65, 0x31, 0x3a, 0x63, 0x33, 0x32, 0x3a, 0x28, 0x40, 0xe8, 0x6a, 0x27, |
|
146 | + | 0xda, 0x6e, 0x0d, 0xe6, 0x2e, 0xab, 0xab, 0x32, 0x95, 0x3e, 0x3b, 0x33, 0xf2, 0xa6, |
|
147 | + | 0x51, 0x18, 0x35, 0xf1, 0x85, 0x1a, 0x1a, 0xcc, 0x51, 0xd7, 0x71, 0xcb, 0x99, 0x31, |
|
148 | + | 0x3a, 0x64, 0x69, 0x31, 0x65, 0x31, 0x3a, 0x68, 0x33, 0x32, 0x3a, 0x28, 0x40, 0xe8, |
|
149 | + | 0x6a, 0x27, 0xda, 0x6e, 0x0d, 0xe6, 0x2e, 0xab, 0xab, 0x32, 0x95, 0x3e, 0x3b, 0x33, |
|
150 | + | 0xf2, 0xa6, 0x51, 0x18, 0x35, 0xf1, 0x85, 0x1a, 0x1a, 0xcc, 0x51, 0xd7, 0x71, 0xcb, |
|
151 | + | 0x99, 0x31, 0x3a, 0x69, 0x69, 0x32, 0x65, 0x31, 0x3a, 0x6d, 0x32, 0x30, 0x3a, 0x21, |
|
152 | + | 0x74, 0x4f, 0x4f, 0x08, 0xdb, 0x23, 0xe0, 0x44, 0x17, 0x8d, 0xaf, 0xb8, 0x27, 0x3a, |
|
153 | + | 0xeb, 0x5e, 0xbe, 0x66, 0x44, 0x31, 0x3a, 0x6e, 0x31, 0x30, 0x3a, 0x5c, 0x77, 0x74, |
|
154 | + | 0xc2, 0x39, 0x69, 0x37, 0x51, 0x87, 0xa5, 0x31, 0x3a, 0x70, 0x33, 0x32, 0x3a, 0x1b, |
|
155 | + | 0xba, 0x9f, 0xcf, 0x4c, 0x81, 0x52, 0xc8, 0x99, 0xed, 0x16, 0x74, 0xec, 0xbf, 0x4a, |
|
156 | + | 0x65, 0x71, 0xc2, 0x71, 0x92, 0x2c, 0x08, 0x84, 0xae, 0x80, 0x9f, 0x91, 0xf0, 0x37, |
|
157 | + | 0xbe, 0xd8, 0xfc, 0x31, 0x3a, 0x74, 0x75, 0x32, 0x37, 0x3a, 0x32, 0x30, 0x31, 0x38, |
|
158 | + | 0x2d, 0x31, 0x31, 0x2d, 0x32, 0x39, 0x54, 0x30, 0x30, 0x3a, 0x30, 0x30, 0x3a, 0x33, |
|
159 | + | 0x30, 0x2e, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x31, 0x3a, 0x78, 0x33, 0x32, |
|
160 | + | 0x3a, 0x75, 0xa9, 0x2b, 0xf5, 0xcf, 0xf3, 0x5d, 0x5b, 0x4d, 0x0c, 0xb8, 0x40, 0xab, |
|
161 | + | 0x61, 0x11, 0x3d, 0xee, 0xab, 0x6f, 0x78, 0x0f, 0x9b, 0x69, 0xfc, 0x48, 0x68, 0xe6, |
|
162 | + | 0xba, 0xac, 0xdc, 0xcb, 0x54, 0x65, 0x31, 0x3a, 0x54, 0x6c, 0x34, 0x33, 0x36, 0x3a, |
|
163 | + | 0x64, 0x31, 0x3a, 0x53, 0x37, 0x31, 0x3a, 0x30, 0x45, 0x02, 0x21, 0x00, 0xc4, 0xf1, |
|
164 | + | 0x85, 0x62, 0xdf, 0x1a, 0x46, 0xb0, 0x0b, 0x9c, 0x50, 0x81, 0x9f, 0x24, 0xaa, 0xf5, |
|
165 | + | 0x83, 0xc8, 0x86, 0xaa, 0x82, 0xcc, 0xb9, 0xdf, 0x27, 0x41, 0xd0, 0x21, 0xba, 0x3d, |
|
166 | + | 0xf7, 0x18, 0x02, 0x20, 0x7e, 0xb2, 0x5b, 0xbd, 0xaa, 0x3c, 0xc5, 0x2a, 0x36, 0x4c, |
|
167 | + | 0x28, 0x77, 0xbb, 0xac, 0x31, 0xb4, 0xa0, 0x22, 0xa2, 0x44, 0x97, 0xaf, 0x90, 0x5b, |
|
168 | + | 0x01, 0xff, 0x24, 0x09, 0xea, 0x85, 0x7f, 0x5c, 0x31, 0x3a, 0x61, 0x6c, 0x64, 0x75, |
|
169 | + | 0x37, 0x3a, 0x74, 0x79, 0x70, 0x65, 0x5f, 0x69, 0x64, 0x75, 0x36, 0x3a, 0x61, 0x74, |
|
170 | + | 0x74, 0x61, 0x63, 0x6b, 0x75, 0x36, 0x3a, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x64, |
|
171 | + | 0x75, 0x36, 0x3a, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x75, 0x33, 0x3a, 0x6f, 0x72, |
|
172 | + | 0x63, 0x75, 0x31, 0x34, 0x3a, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x5f, 0x61, 0x64, |
|
173 | + | 0x64, 0x72, 0x65, 0x73, 0x73, 0x32, 0x30, 0x3a, 0xc2, 0xa8, 0x60, 0x14, 0x07, 0x3d, |
|
174 | + | 0x66, 0x2a, 0x4a, 0x9b, 0xfc, 0xf9, 0xcb, 0x54, 0x26, 0x3d, 0xfa, 0x4f, 0x5c, 0xbc, |
|
175 | + | 0x75, 0x36, 0x3a, 0x77, 0x65, 0x61, 0x70, 0x6f, 0x6e, 0x75, 0x34, 0x3a, 0x77, 0x61, |
|
176 | + | 0x6e, 0x64, 0x65, 0x65, 0x64, 0x75, 0x37, 0x3a, 0x74, 0x79, 0x70, 0x65, 0x5f, 0x69, |
|
177 | + | 0x64, 0x75, 0x35, 0x3a, 0x73, 0x6c, 0x65, 0x65, 0x70, 0x75, 0x36, 0x3a, 0x76, 0x61, |
|
178 | + | 0x6c, 0x75, 0x65, 0x73, 0x64, 0x75, 0x37, 0x3a, 0x7a, 0x6f, 0x6e, 0x65, 0x5f, 0x69, |
|
179 | + | 0x64, 0x69, 0x31, 0x30, 0x65, 0x65, 0x65, 0x65, 0x31, 0x3a, 0x67, 0x33, 0x32, 0x3a, |
|
180 | + | 0xd6, 0x93, 0xda, 0x38, 0x66, 0xa3, 0x4d, 0x65, 0x9e, 0x01, 0x4f, 0x97, 0xc8, 0xfe, |
|
181 | + | 0xb0, 0x8a, 0xfe, 0x2e, 0x97, 0xc9, 0x9e, 0x3f, 0x33, 0x89, 0xda, 0x02, 0x5f, 0xd0, |
|
182 | + | 0x66, 0x5c, 0x62, 0x1c, 0x31, 0x3a, 0x6e, 0x69, 0x30, 0x65, 0x31, 0x3a, 0x70, 0x36, |
|
183 | + | 0x35, 0x3a, 0x04, 0x46, 0x11, 0x5b, 0x01, 0x31, 0xba, 0xcc, 0xf9, 0x4a, 0x58, 0x56, |
|
184 | + | 0xed, 0xe8, 0x71, 0x29, 0x5f, 0x6f, 0x3d, 0x35, 0x2e, 0x68, 0x47, 0xcd, 0xa9, 0xc0, |
|
185 | + | 0x3e, 0x89, 0xfe, 0x09, 0xf7, 0x32, 0x80, 0x87, 0x11, 0xec, 0x97, 0xaf, 0x6e, 0x34, |
|
186 | + | 0x1f, 0x11, 0x0a, 0x32, 0x6d, 0xa1, 0xbd, 0xb8, 0x1f, 0x5a, 0xe3, 0xba, 0xdf, 0x76, |
|
187 | + | 0xa9, 0x0b, 0x22, 0xc8, 0xc4, 0x91, 0xae, 0xd3, 0xaa, 0xa2, 0x96, 0x31, 0x3a, 0x73, |
|
188 | + | 0x32, 0x30, 0x3a, 0xc2, 0xa8, 0x60, 0x14, 0x07, 0x3d, 0x66, 0x2a, 0x4a, 0x9b, 0xfc, |
|
189 | + | 0xf9, 0xcb, 0x54, 0x26, 0x3d, 0xfa, 0x4f, 0x5c, 0xbc, 0x31, 0x3a, 0x74, 0x75, 0x32, |
|
190 | + | 0x37, 0x3a, 0x32, 0x30, 0x31, 0x38, 0x2d, 0x31, 0x31, 0x2d, 0x32, 0x31, 0x54, 0x30, |
|
191 | + | 0x30, 0x3a, 0x30, 0x30, 0x3a, 0x30, 0x30, 0x2e, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, |
|
192 | + | 0x5a, 0x31, 0x3a, 0x75, 0x6c, 0x32, 0x30, 0x3a, 0xc2, 0xa8, 0x60, 0x14, 0x07, 0x3d, |
|
193 | + | 0x66, 0x2a, 0x4a, 0x9b, 0xfc, 0xf9, 0xcb, 0x54, 0x26, 0x3d, 0xfa, 0x4f, 0x5c, 0xbc, |
|
194 | + | 0x65, 0x65, 0x65, 0x65, |
|
195 | 195 | }; |
|
196 | 196 | ||
197 | 197 | Block<PolymorphicAction<BaseAction>> actual = |
@@ -338,19 +338,22 @@
Loading
338 | 338 | ||
339 | 339 | Transaction<DumbAction>[] blockIdx2Txs = |
|
340 | 340 | { |
|
341 | + | // Note that these timestamps in themselves does not have any meanings but are |
|
342 | + | // only arbitrary. These purpose to make their evaluation order in a block |
|
343 | + | // equal to the order we (the test) intend: |
|
341 | 344 | Transaction<DumbAction>.Create( |
|
342 | 345 | 0, |
|
343 | 346 | _fx.TxFixture.PrivateKey1, |
|
344 | 347 | _fx.Genesis.Hash, |
|
345 | 348 | new[] { MakeAction(addresses[0], 'D') }, |
|
346 | - | timestamp: DateTimeOffset.MinValue.AddSeconds(3) |
|
349 | + | timestamp: DateTimeOffset.MinValue.AddSeconds(1) |
|
347 | 350 | ), |
|
348 | 351 | Transaction<DumbAction>.Create( |
|
349 | 352 | 0, |
|
350 | 353 | _fx.TxFixture.PrivateKey2, |
|
351 | 354 | _fx.Genesis.Hash, |
|
352 | 355 | new[] { MakeAction(addresses[3], 'E') }, |
|
353 | - | timestamp: DateTimeOffset.MinValue.AddSeconds(4) |
|
356 | + | timestamp: DateTimeOffset.MinValue.AddSeconds(3) |
|
354 | 357 | ), |
|
355 | 358 | Transaction<DumbAction>.Create( |
|
356 | 359 | 0, |
@@ -368,7 +371,7 @@
Loading
368 | 371 | recordRandom: true |
|
369 | 372 | ), |
|
370 | 373 | }, |
|
371 | - | timestamp: DateTimeOffset.MinValue.AddSeconds(6) |
|
374 | + | timestamp: DateTimeOffset.MinValue.AddSeconds(5) |
|
372 | 375 | ), |
|
373 | 376 | }; |
|
374 | 377 | i = 0; |
@@ -528,7 +531,10 @@
Loading
528 | 531 | miner: _fx.Next.Miner, |
|
529 | 532 | previousHash: _fx.Next.PreviousHash, |
|
530 | 533 | timestamp: _fx.Next.Timestamp, |
|
531 | - | transactions: _fx.Next.Transactions); |
|
534 | + | transactions: _fx.Next.Transactions, |
|
535 | + | preEvaluationHash: _fx.Next.PreEvaluationHash, |
|
536 | + | protocolVersion: _fx.Next.ProtocolVersion |
|
537 | + | ); |
|
532 | 538 | ||
533 | 539 | Assert.Throws<InvalidBlockNonceException>(() => |
|
534 | 540 | invalidBlock.Validate(DateTimeOffset.UtcNow)); |
@@ -629,7 +635,7 @@
Loading
629 | 635 | } |
|
630 | 636 | ||
631 | 637 | [Fact] |
|
632 | - | public void CanConvertToRaw() |
|
638 | + | public void ConvertToRaw() |
|
633 | 639 | { |
|
634 | 640 | RawBlock rawGenesis = _fx.Genesis.ToRawBlock(); |
|
635 | 641 | Assert.Equal(0, rawGenesis.Header.Index); |
@@ -649,9 +655,9 @@
Loading
649 | 655 | AssertBytesEqual( |
|
650 | 656 | new byte[32] |
|
651 | 657 | { |
|
652 | - | 0xd4, 0xf3, 0x58, 0x34, 0xe2, 0x7d, 0x5a, 0xb4, 0x59, 0xa4, 0xd4, 0x01, 0xe9, |
|
653 | - | 0xa0, 0x82, 0x68, 0xe3, 0xfe, 0x32, 0x1b, 0x8c, 0x68, 0x50, 0x75, 0xae, 0xc5, |
|
654 | - | 0xbd, 0x5d, 0x18, 0xd6, 0x42, 0xaa, |
|
658 | + | 0xd6, 0x93, 0xda, 0x38, 0x66, 0xa3, 0x4d, 0x65, 0x9e, 0x01, 0x4f, 0x97, |
|
659 | + | 0xc8, 0xfe, 0xb0, 0x8a, 0xfe, 0x2e, 0x97, 0xc9, 0x9e, 0x3f, 0x33, 0x89, |
|
660 | + | 0xda, 0x02, 0x5f, 0xd0, 0x66, 0x5c, 0x62, 0x1c, |
|
655 | 661 | }, |
|
656 | 662 | rawGenesis.Header.Hash.ToArray() |
|
657 | 663 | ); |
@@ -669,11 +675,11 @@
Loading
669 | 675 | Assert.Empty(rawNext.Transactions); |
|
670 | 676 | Assert.Empty(rawNext.Header.TxHash); |
|
671 | 677 | AssertBytesEqual( |
|
672 | - | new byte[32] |
|
678 | + | new byte[] |
|
673 | 679 | { |
|
674 | - | 0x1c, 0xd4, 0x45, 0x16, 0x24, 0xef, 0x9c, 0x79, 0xe2, 0xc2, 0xfb, 0x5a, 0x8e, |
|
675 | - | 0x79, 0x1e, 0x4f, 0xa5, 0x6a, 0x7d, 0x8c, 0x61, 0x0c, 0x14, 0xa8, 0xa3, 0x4a, |
|
676 | - | 0xe1, 0x75, 0xb5, 0x20, 0x5c, 0xf7, |
|
680 | + | 0x1b, 0xba, 0x9f, 0xcf, 0x4c, 0x81, 0x52, 0xc8, 0x99, 0xed, 0x16, 0x74, 0xec, |
|
681 | + | 0xbf, 0x4a, 0x65, 0x71, 0xc2, 0x71, 0x92, 0x2c, 0x08, 0x84, 0xae, 0x80, 0x9f, |
|
682 | + | 0x91, 0xf0, 0x37, 0xbe, 0xd8, 0xfc, |
|
677 | 683 | }, |
|
678 | 684 | rawNext.Header.Hash.ToArray() |
|
679 | 685 | ); |
@@ -690,20 +696,20 @@
Loading
690 | 696 | ); |
|
691 | 697 | Assert.Single(rawHasText.Transactions); |
|
692 | 698 | AssertBytesEqual( |
|
693 | - | new byte[32] |
|
699 | + | new byte[] |
|
694 | 700 | { |
|
695 | - | 0x97, 0x3c, 0xa5, 0xff, 0xce, 0x89, 0x84, 0xc0, 0x39, 0xe6, 0x3f, 0x2b, 0xee, |
|
696 | - | 0x2f, 0x01, 0x67, 0x00, 0x51, 0x00, 0xa0, 0xfb, 0xa4, 0x71, 0x4f, 0xf6, 0xfb, |
|
697 | - | 0x67, 0xe0, 0xaf, 0x61, 0x53, 0x00, |
|
701 | + | 0x75, 0xa9, 0x2b, 0xf5, 0xcf, 0xf3, 0x5d, 0x5b, 0x4d, 0x0c, 0xb8, 0x40, 0xab, |
|
702 | + | 0x61, 0x11, 0x3d, 0xee, 0xab, 0x6f, 0x78, 0x0f, 0x9b, 0x69, 0xfc, 0x48, 0x68, |
|
703 | + | 0xe6, 0xba, 0xac, 0xdc, 0xcb, 0x54, |
|
698 | 704 | }, |
|
699 | 705 | rawHasText.Header.TxHash.ToArray() |
|
700 | 706 | ); |
|
701 | 707 | AssertBytesEqual( |
|
702 | 708 | new byte[32] |
|
703 | 709 | { |
|
704 | - | 0x22, 0xe1, 0x3b, 0xb5, 0x46, 0x65, 0x91, 0x34, 0x28, 0xbc, 0x55, 0x86, 0xce, |
|
705 | - | 0xbd, 0x50, 0xdc, 0x25, 0x50, 0xb0, 0x36, 0xa6, 0x18, 0xe9, 0xb0, 0x5d, 0xb1, |
|
706 | - | 0x1c, 0x76, 0xad, 0xb0, 0x0a, 0xd7, |
|
710 | + | 0x28, 0x40, 0xe8, 0x6a, 0x27, 0xda, 0x6e, 0x0d, 0xe6, 0x2e, 0xab, 0xab, 0x32, |
|
711 | + | 0x95, 0x3e, 0x3b, 0x33, 0xf2, 0xa6, 0x51, 0x18, 0x35, 0xf1, 0x85, 0x1a, 0x1a, |
|
712 | + | 0xcc, 0x51, 0xd7, 0x71, 0xcb, 0x99, |
|
707 | 713 | }, |
|
708 | 714 | rawHasText.Header.Hash.ToArray() |
|
709 | 715 | ); |
@@ -740,19 +746,19 @@
Loading
740 | 746 | var codec = new Codec(); |
|
741 | 747 | // Case of a block with no any txs, contained state root. |
|
742 | 748 | // Size of RawBlock |
|
743 | - | Assert.Equal(208, emptyBlock.Serialize().Length); |
|
749 | + | Assert.Equal(214, emptyBlock.Serialize().Length); |
|
744 | 750 | // Size of BlockDigest |
|
745 | - | Assert.Equal(208, emptyBlock.ToBlockDigest().Serialize().Length); |
|
751 | + | Assert.Equal(214, emptyBlock.ToBlockDigest().Serialize().Length); |
|
746 | 752 | // Size of BlockHeader |
|
747 | - | Assert.Equal(203, codec.Encode(emptyBlock.Header.ToBencodex()).Length); |
|
753 | + | Assert.Equal(209, codec.Encode(emptyBlock.Header.ToBencodex()).Length); |
|
748 | 754 | ||
749 | 755 | // Case of a block with txs, not contained state root. |
|
750 | 756 | // Size of RawBlock |
|
751 | - | Assert.Equal(697, txBlock.Serialize().Length); |
|
757 | + | Assert.Equal(704, txBlock.Serialize().Length); |
|
752 | 758 | // Size of BlockDigest |
|
753 | - | Assert.Equal(293, txBlock.ToBlockDigest().Serialize().Length); |
|
759 | + | Assert.Equal(299, txBlock.ToBlockDigest().Serialize().Length); |
|
754 | 760 | // Size of BlockHeader |
|
755 | - | Assert.Equal(248, codec.Encode(txBlock.Header.ToBencodex()).Length); |
|
761 | + | Assert.Equal(254, codec.Encode(txBlock.Header.ToBencodex()).Length); |
|
756 | 762 | } |
|
757 | 763 | ||
758 | 764 | [Fact] |
@@ -786,7 +792,7 @@
Loading
786 | 792 | timestamp: DateTimeOffset.UtcNow, |
|
787 | 793 | transactions: new Transaction<DumbAction>[0] |
|
788 | 794 | ); |
|
789 | - | Assert.Equal(140, block.BytesLength); |
|
795 | + | Assert.Equal(146, block.BytesLength); |
|
790 | 796 | } |
|
791 | 797 | ||
792 | 798 | [Fact] |
@@ -264,5 +264,21 @@
Loading
264 | 264 | return hashCode; |
|
265 | 265 | } |
|
266 | 266 | } |
|
267 | + | ||
268 | + | public override string ToString() |
|
269 | + | { |
|
270 | + | const string T = "true", F = "false"; |
|
271 | + | string transfer = Transfer is Tuple<Address, Address, BigInteger> t |
|
272 | + | ? $"({t.Item1}, {t.Item2}, {t.Item3})" |
|
273 | + | : "null"; |
|
274 | + | return $"{nameof(DumbAction)} {{ " + |
|
275 | + | $"{nameof(TargetAddress)} = {TargetAddress}, " + |
|
276 | + | $"{nameof(Item)} = {Item ?? string.Empty}, " + |
|
277 | + | $"{nameof(RecordRehearsal)} = {(RecordRehearsal ? T : F)}, " + |
|
278 | + | $"{nameof(RecordRandom)} = {(RecordRandom ? T : F)}, " + |
|
279 | + | $"{nameof(Idempotent)} = {(Idempotent ? T : F)}, " + |
|
280 | + | $"{nameof(Transfer)} = {transfer} " + |
|
281 | + | "}"; |
|
282 | + | } |
|
267 | 283 | } |
|
268 | 284 | } |
@@ -17,27 +17,29 @@
Loading
17 | 17 | { |
|
18 | 18 | internal const string TimestampFormat = "yyyy-MM-ddTHH:mm:ss.ffffffZ"; |
|
19 | 19 | ||
20 | - | private static readonly byte[] IndexKey = { 0x69 }; // 'i' |
|
20 | + | internal static readonly byte[] ProtocolVersionKey = { 0x00 }; |
|
21 | 21 | ||
22 | - | private static readonly byte[] TimestampKey = { 0x74 }; // 't' |
|
22 | + | internal static readonly byte[] IndexKey = { 0x69 }; // 'i' |
|
23 | 23 | ||
24 | - | private static readonly byte[] DifficultyKey = { 0x64 }; // 'd' |
|
24 | + | internal static readonly byte[] TimestampKey = { 0x74 }; // 't' |
|
25 | 25 | ||
26 | - | private static readonly byte[] TotalDifficultyKey = { 0x54 }; // 'T' |
|
26 | + | internal static readonly byte[] DifficultyKey = { 0x64 }; // 'd' |
|
27 | 27 | ||
28 | - | private static readonly byte[] NonceKey = { 0x6e }; // 'n' |
|
28 | + | internal static readonly byte[] TotalDifficultyKey = { 0x54 }; // 'T' |
|
29 | 29 | ||
30 | - | private static readonly byte[] MinerKey = { 0x6d }; // 'm' |
|
30 | + | internal static readonly byte[] NonceKey = { 0x6e }; // 'n' |
|
31 | 31 | ||
32 | - | private static readonly byte[] PreviousHashKey = { 0x70 }; // 'p' |
|
32 | + | internal static readonly byte[] MinerKey = { 0x6d }; // 'm' |
|
33 | 33 | ||
34 | - | private static readonly byte[] TxHashKey = { 0x78 }; // 'x' |
|
34 | + | internal static readonly byte[] PreviousHashKey = { 0x70 }; // 'p' |
|
35 | 35 | ||
36 | - | private static readonly byte[] HashKey = { 0x68 }; // 'h' |
|
36 | + | internal static readonly byte[] TxHashKey = { 0x78 }; // 'x' |
|
37 | 37 | ||
38 | - | private static readonly byte[] StateRootHashKey = { 0x73 }; // 's' |
|
38 | + | internal static readonly byte[] HashKey = { 0x68 }; // 'h' |
|
39 | 39 | ||
40 | - | private static readonly byte[] PreEvaluationHashKey = { 0x63 }; // 'c' |
|
40 | + | internal static readonly byte[] StateRootHashKey = { 0x73 }; // 's' |
|
41 | + | ||
42 | + | internal static readonly byte[] PreEvaluationHashKey = { 0x63 }; // 'c' |
|
41 | 43 | ||
42 | 44 | private static readonly TimeSpan TimestampThreshold = |
|
43 | 45 | TimeSpan.FromSeconds(15); |
@@ -45,6 +47,8 @@
Loading
45 | 47 | /// <summary> |
|
46 | 48 | /// Creates a <see cref="BlockHeader"/> instance. |
|
47 | 49 | /// </summary> |
|
50 | + | /// <param name="protocolVersion">The protocol version. Goes to the <see |
|
51 | + | /// cref="ProtocolVersion"/>.</param> |
|
48 | 52 | /// <param name="index">The height of the block. Goes to the <see cref="Index"/>. |
|
49 | 53 | /// </param> |
|
50 | 54 | /// <param name="timestamp">The time this block is created. |
@@ -71,6 +75,7 @@
Loading
71 | 75 | /// <param name="stateRootHash">The <see cref="ITrie.Hash"/> of the states on the block. |
|
72 | 76 | /// </param> |
|
73 | 77 | public BlockHeader( |
|
78 | + | int protocolVersion, |
|
74 | 79 | long index, |
|
75 | 80 | string timestamp, |
|
76 | 81 | ImmutableArray<byte> nonce, |
@@ -83,6 +88,7 @@
Loading
83 | 88 | ImmutableArray<byte> preEvaluationHash, |
|
84 | 89 | ImmutableArray<byte> stateRootHash) |
|
85 | 90 | { |
|
91 | + | ProtocolVersion = protocolVersion; |
|
86 | 92 | Index = index; |
|
87 | 93 | Timestamp = timestamp; |
|
88 | 94 | Nonce = nonce; |
@@ -98,6 +104,9 @@
Loading
98 | 104 | ||
99 | 105 | public BlockHeader(Bencodex.Types.Dictionary dict) |
|
100 | 106 | { |
|
107 | + | ProtocolVersion = dict.ContainsKey(ProtocolVersionKey) |
|
108 | + | ? (int)dict.GetValue<Integer>(ProtocolVersionKey) |
|
109 | + | : 0; |
|
101 | 110 | Index = dict.GetValue<Integer>(IndexKey); |
|
102 | 111 | Timestamp = dict.GetValue<Text>(TimestampKey); |
|
103 | 112 | Difficulty = dict.GetValue<Integer>(DifficultyKey); |
@@ -129,6 +138,11 @@
Loading
129 | 138 | : ImmutableArray<byte>.Empty; |
|
130 | 139 | } |
|
131 | 140 | ||
141 | + | /// <summary> |
|
142 | + | /// The protocol version number. |
|
143 | + | /// </summary> |
|
144 | + | public int ProtocolVersion { get; } |
|
145 | + | ||
132 | 146 | public long Index { get; } |
|
133 | 147 | ||
134 | 148 | public string Timestamp { get; } |
@@ -196,6 +210,11 @@
Loading
196 | 210 | .Add(NonceKey, Nonce.ToArray()) |
|
197 | 211 | .Add(HashKey, Hash.ToArray()); |
|
198 | 212 | ||
213 | + | if (ProtocolVersion != 0) |
|
214 | + | { |
|
215 | + | dict = dict.Add(ProtocolVersionKey, ProtocolVersion); |
|
216 | + | } |
|
217 | + | ||
199 | 218 | if (Miner.Any()) |
|
200 | 219 | { |
|
201 | 220 | dict = dict.Add(MinerKey, Miner.ToArray()); |
@@ -226,6 +245,14 @@
Loading
226 | 245 | ||
227 | 246 | internal void Validate(DateTimeOffset currentTime) |
|
228 | 247 | { |
|
248 | + | if (ProtocolVersion < 0) |
|
249 | + | { |
|
250 | + | throw new InvalidBlockProtocolVersionException( |
|
251 | + | ProtocolVersion, |
|
252 | + | $"A block's protocol version cannot be less than zero: {ProtocolVersion}." |
|
253 | + | ); |
|
254 | + | } |
|
255 | + | ||
229 | 256 | DateTimeOffset ts = DateTimeOffset.ParseExact( |
|
230 | 257 | Timestamp, |
|
231 | 258 | TimestampFormat, |
@@ -21,6 +21,11 @@
Loading
21 | 21 | public class Block<T> |
|
22 | 22 | where T : IAction, new() |
|
23 | 23 | { |
|
24 | + | /// <summary> |
|
25 | + | /// The most latest protocol version. |
|
26 | + | /// </summary> |
|
27 | + | public const int CurrentProtocolVersion = 1; |
|
28 | + | ||
24 | 29 | private int _bytesLength; |
|
25 | 30 | ||
26 | 31 | /// <summary> |
@@ -51,6 +56,8 @@
Loading
51 | 56 | /// Automatically determined if <c>null</c> is passed (which is default).</param> |
|
52 | 57 | /// <param name="stateRootHash">The <see cref="ITrie.Hash"/> of the states on the block. |
|
53 | 58 | /// </param> |
|
59 | + | /// <param name="protocolVersion">The protocol version. <see cref="CurrentProtocolVersion"/> |
|
60 | + | /// by default.</param> |
|
54 | 61 | /// <seealso cref="Mine"/> |
|
55 | 62 | public Block( |
|
56 | 63 | long index, |
@@ -62,8 +69,10 @@
Loading
62 | 69 | DateTimeOffset timestamp, |
|
63 | 70 | IEnumerable<Transaction<T>> transactions, |
|
64 | 71 | HashDigest<SHA256>? preEvaluationHash = null, |
|
65 | - | HashDigest<SHA256>? stateRootHash = null) |
|
72 | + | HashDigest<SHA256>? stateRootHash = null, |
|
73 | + | int protocolVersion = CurrentProtocolVersion) |
|
66 | 74 | { |
|
75 | + | ProtocolVersion = protocolVersion; |
|
67 | 76 | Index = index; |
|
68 | 77 | Difficulty = difficulty; |
|
69 | 78 | TotalDifficulty = totalDifficulty; |
@@ -126,9 +135,12 @@
Loading
126 | 135 | { |
|
127 | 136 | } |
|
128 | 137 | ||
138 | + | // FIXME: Should this necessarily be a public constructor? |
|
139 | + | // See also <https://github.com/planetarium/libplanet/issues/1146>. |
|
129 | 140 | public Block( |
|
130 | 141 | Block<T> block, |
|
131 | - | HashDigest<SHA256>? stateRootHash) |
|
142 | + | HashDigest<SHA256>? stateRootHash |
|
143 | + | ) |
|
132 | 144 | : this( |
|
133 | 145 | block.Index, |
|
134 | 146 | block.Difficulty, |
@@ -139,39 +151,47 @@
Loading
139 | 151 | block.Timestamp, |
|
140 | 152 | block.Transactions, |
|
141 | 153 | block.PreEvaluationHash, |
|
142 | - | stateRootHash) |
|
154 | + | stateRootHash, |
|
155 | + | protocolVersion: block.ProtocolVersion |
|
156 | + | ) |
|
143 | 157 | { |
|
144 | 158 | } |
|
145 | 159 | ||
146 | 160 | private Block(RawBlock rb) |
|
147 | 161 | : this( |
|
162 | + | #pragma warning disable SA1118 |
|
163 | + | rb.Header.ProtocolVersion, |
|
148 | 164 | new HashDigest<SHA256>(rb.Header.Hash), |
|
149 | 165 | rb.Header.Index, |
|
150 | 166 | rb.Header.Difficulty, |
|
151 | 167 | rb.Header.TotalDifficulty, |
|
152 | 168 | new Nonce(rb.Header.Nonce.ToArray()), |
|
153 | 169 | rb.Header.Miner.Any() ? new Address(rb.Header.Miner) : (Address?)null, |
|
154 | - | #pragma warning disable MEN002 // Line is too long |
|
155 | - | rb.Header.PreviousHash.Any() ? new HashDigest<SHA256>(rb.Header.PreviousHash) : (HashDigest<SHA256>?)null, |
|
156 | - | #pragma warning restore MEN002 // Line is too long |
|
170 | + | rb.Header.PreviousHash.Any() |
|
171 | + | ? new HashDigest<SHA256>(rb.Header.PreviousHash) |
|
172 | + | : (HashDigest<SHA256>?)null, |
|
157 | 173 | DateTimeOffset.ParseExact( |
|
158 | 174 | rb.Header.Timestamp, |
|
159 | 175 | BlockHeader.TimestampFormat, |
|
160 | 176 | CultureInfo.InvariantCulture).ToUniversalTime(), |
|
161 | - | #pragma warning disable MEN002 // Line is too long |
|
162 | - | rb.Header.TxHash.Any() ? new HashDigest<SHA256>(rb.Header.TxHash) : (HashDigest<SHA256>?)null, |
|
163 | - | #pragma warning restore MEN002 // Line is too long |
|
177 | + | rb.Header.TxHash.Any() |
|
178 | + | ? new HashDigest<SHA256>(rb.Header.TxHash) |
|
179 | + | : (HashDigest<SHA256>?)null, |
|
164 | 180 | rb.Transactions |
|
165 | 181 | .Select(tx => Transaction<T>.Deserialize(tx.ToArray())) |
|
166 | 182 | .ToList(), |
|
167 | - | #pragma warning disable MEN002 // Line is too long |
|
168 | - | rb.Header.PreEvaluationHash.Any() ? new HashDigest<SHA256>(rb.Header.PreEvaluationHash) : (HashDigest<SHA256>?)null, |
|
169 | - | rb.Header.StateRootHash.Any() ? new HashDigest<SHA256>(rb.Header.StateRootHash) : (HashDigest<SHA256>?)null) |
|
170 | - | #pragma warning restore MEN002 // Line is too long |
|
183 | + | rb.Header.PreEvaluationHash.Any() |
|
184 | + | ? new HashDigest<SHA256>(rb.Header.PreEvaluationHash) |
|
185 | + | : (HashDigest<SHA256>?)null, |
|
186 | + | rb.Header.StateRootHash.Any() |
|
187 | + | ? new HashDigest<SHA256>(rb.Header.StateRootHash) |
|
188 | + | : (HashDigest<SHA256>?)null) |
|
189 | + | #pragma warning restore SA1118 |
|
171 | 190 | { |
|
172 | 191 | } |
|
173 | 192 | ||
174 | 193 | private Block( |
|
194 | + | int protocolVersion, |
|
175 | 195 | HashDigest<SHA256> hash, |
|
176 | 196 | long index, |
|
177 | 197 | long difficulty, |
@@ -186,6 +206,7 @@
Loading
186 | 206 | HashDigest<SHA256>? stateRootHash |
|
187 | 207 | ) |
|
188 | 208 | { |
|
209 | + | ProtocolVersion = protocolVersion; |
|
189 | 210 | Index = index; |
|
190 | 211 | Difficulty = difficulty; |
|
191 | 212 | TotalDifficulty = totalDifficulty; |
@@ -205,6 +226,12 @@
Loading
205 | 226 | Transactions = transactions.ToImmutableArray(); |
|
206 | 227 | } |
|
207 | 228 | ||
229 | + | /// <summary> |
|
230 | + | /// The protocol version number. |
|
231 | + | /// </summary> |
|
232 | + | [IgnoreDuringEquals] |
|
233 | + | public int ProtocolVersion { get; } |
|
234 | + | ||
208 | 235 | /// <summary> |
|
209 | 236 | /// <see cref="Hash"/> is derived from a serialized <see cref="Block{T}"/> |
|
210 | 237 | /// after <see cref="Transaction{T}.Actions"/> are evaluated. |
@@ -288,6 +315,7 @@
Loading
288 | 315 | ||
289 | 316 | // FIXME: When hash is not assigned, should throw an exception. |
|
290 | 317 | return new BlockHeader( |
|
318 | + | protocolVersion: ProtocolVersion, |
|
291 | 319 | index: Index, |
|
292 | 320 | timestamp: timestampAsString, |
|
293 | 321 | nonce: Nonce.ToByteArray().ToImmutableArray(), |
@@ -324,6 +352,7 @@
Loading
324 | 352 | /// <param name="timestamp">The <see cref="DateTimeOffset"/> when mining started.</param> |
|
325 | 353 | /// <param name="transactions"><see cref="Transaction{T}"/>s that are going to be included |
|
326 | 354 | /// in the block.</param> |
|
355 | + | /// <param name="protocolVersion">The protocol version.</param> |
|
327 | 356 | /// <param name="cancellationToken"> |
|
328 | 357 | /// A cancellation token used to propagate notification that this |
|
329 | 358 | /// operation should be canceled.</param> |
@@ -336,6 +365,7 @@
Loading
336 | 365 | HashDigest<SHA256>? previousHash, |
|
337 | 366 | DateTimeOffset timestamp, |
|
338 | 367 | IEnumerable<Transaction<T>> transactions, |
|
368 | + | int protocolVersion = CurrentProtocolVersion, |
|
339 | 369 | CancellationToken cancellationToken = default(CancellationToken)) |
|
340 | 370 | { |
|
341 | 371 | var txs = transactions.OrderBy(tx => tx.Id).ToImmutableArray(); |
@@ -347,7 +377,8 @@
Loading
347 | 377 | miner, |
|
348 | 378 | previousHash, |
|
349 | 379 | timestamp, |
|
350 | - | txs); |
|
380 | + | txs, |
|
381 | + | protocolVersion: protocolVersion); |
|
351 | 382 | ||
352 | 383 | // Poor man' way to optimize stamp... |
|
353 | 384 | // FIXME: We need to rather reorganize the serialization layout. |
@@ -658,6 +689,11 @@
Loading
658 | 689 | .Add("difficulty", Difficulty) |
|
659 | 690 | .Add("nonce", Nonce.ToByteArray()); |
|
660 | 691 | ||
692 | + | if (ProtocolVersion != 0) |
|
693 | + | { |
|
694 | + | dict = dict.Add("protocol_version", ProtocolVersion); |
|
695 | + | } |
|
696 | + | ||
661 | 697 | if (!(Miner is null)) |
|
662 | 698 | { |
|
663 | 699 | dict = dict.Add("reward_beneficiary", Miner.Value.ToByteArray()); |
Files | Coverage |
---|---|
Libplanet | 84.84% |
Libplanet.Analyzers.Tests | 84.07% |
Libplanet.RocksDBStore | 92.12% |
Libplanet.RocksDBStore.Tests | 88.00% |
Libplanet.Stun.Tests/Stun | 99.56% |
Libplanet.Stun/Stun | 78.44% |
Libplanet.Tests | 89.27% |
Libplanet.Analyzers/ActionAnalyzer.cs | 82.58% |
Project Totals (347 files) | 87.41% |
20210108.4
20210108.4
20210108.4
20210108.4
Sunburst
The inner-most circle is the entire project, moving away from the center are folders then, finally, a single file.
The size and color of each slice is representing the number of statements and the coverage, respectively.
Icicle
The top section represents the entire project. Proceeding with folders and finally individual files.
The size and color of each slice is representing the number of statements and the coverage, respectively.