Skip to content

Commit

Permalink
Update state ref even if block state exists
Browse files Browse the repository at this point in the history
  • Loading branch information
earlbread committed Dec 5, 2019
1 parent f762de3 commit 6e9fca1
Show file tree
Hide file tree
Showing 4 changed files with 62 additions and 25 deletions.
3 changes: 3 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,8 @@ To be released.
- Fixed a bug where the canonical chain could be deleted if `Swarm<T>` failed
to download blocks due to network connection. [[#675]]
- Fixed bug that re-download block from scratch in preloading. [[#685]]
- Fixed a bug where state references become outdated if a chain is forked
and then adding existing blocks into it. [[#704]]

[#662]: https://github.com/planetarium/libplanet/pull/662
[#665]: https://github.com/planetarium/libplanet/pull/665
Expand All @@ -81,6 +83,7 @@ To be released.
[#692]: https://github.com/planetarium/libplanet/pull/692
[#694]: https://github.com/planetarium/libplanet/pull/694
[#701]: https://github.com/planetarium/libplanet/pull/701
[#704]: https://github.com/planetarium/libplanet/pull/704
[#706]: https://github.com/planetarium/libplanet/pull/706


Expand Down
27 changes: 27 additions & 0 deletions Libplanet.Tests/Blockchain/BlockChainTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -633,6 +633,33 @@ public void ForkChainWithIncompleteBlockStates()
Assert.Equal(6, forked.Count);
}

[Fact]
public async Task StateAfterForkingAndAddingExistingBlock()
{
var miner = _fx.Address1;
var privateKey = new PrivateKey();
var address = privateKey.PublicKey.ToAddress();
var actions1 = new[] { new DumbAction(address, "foo") };
var actions2 = new[] { new DumbAction(address, "bar") };

_blockChain.MakeTransaction(privateKey, actions1);
var b1 = await _blockChain.MineBlock(miner);

_blockChain.MakeTransaction(privateKey, actions2);
var b2 = await _blockChain.MineBlock(miner);
var state = _blockChain.GetState(address);

Assert.Equal((Text)"foo,bar", state);

var forked = _blockChain.Fork(b1.Hash);
state = forked.GetState(address);
Assert.Equal((Text)"foo", state);

forked.Append(b2);
state = forked.GetState(address);
Assert.Equal((Text)"foo,bar", state);
}

[Fact]
public void ForkStateReferences()
{
Expand Down
50 changes: 26 additions & 24 deletions Libplanet/Blockchain/BlockChain.cs
Original file line number Diff line number Diff line change
Expand Up @@ -835,18 +835,16 @@ internal IReadOnlyList<ActionEvaluation> ExecuteActions(Block<T> block)
{
_logger.Debug("Execute action in block {blockIndex}: {block}", block?.Index, block);
IReadOnlyList<ActionEvaluation> evaluations = null;
if (Store.GetBlockStates(block.Hash) is null)
evaluations = EvaluateActions(block);

_rwlock.EnterWriteLock();
try
{
evaluations = EvaluateActions(block);
_rwlock.EnterWriteLock();
try
{
SetStates(block, evaluations, buildStateReferences: true);
}
finally
{
_rwlock.ExitWriteLock();
}
SetStates(block, evaluations, buildStateReferences: true);
}
finally
{
_rwlock.ExitWriteLock();
}

return evaluations;
Expand Down Expand Up @@ -1247,26 +1245,30 @@ internal void SetStates(
bool buildStateReferences
)
{
HashDigest<SHA256> blockHash = block.Hash;
IAccountStateDelta lastStates = actionEvaluations.Count > 0
? actionEvaluations[actionEvaluations.Count - 1].OutputStates
: null;
ImmutableHashSet<Address> updatedAddresses =
actionEvaluations.Select(
a => a.OutputStates.UpdatedAddresses
).Aggregate(
ImmutableHashSet<Address>.Empty,
(a, b) => a.Union(b)
);
ImmutableDictionary<Address, IValue> totalDelta =
updatedAddresses.Select(
a => new KeyValuePair<Address, IValue>(
a,
lastStates?.GetState(a)
)
).ToImmutableDictionary();

Store.SetBlockStates(blockHash, totalDelta);

if (Store.GetBlockStates(block.Hash) is null)
{
HashDigest<SHA256> blockHash = block.Hash;
IAccountStateDelta lastStates = actionEvaluations.Count > 0
? actionEvaluations[actionEvaluations.Count - 1].OutputStates
: null;
ImmutableDictionary<Address, IValue> totalDelta =
updatedAddresses.Select(
a => new KeyValuePair<Address, IValue>(
a,
lastStates?.GetState(a)
)
).ToImmutableDictionary();

Store.SetBlockStates(blockHash, totalDelta);
}

if (buildStateReferences)
{
Expand Down
7 changes: 6 additions & 1 deletion Libplanet/Store/DefaultStore.cs
Original file line number Diff line number Diff line change
Expand Up @@ -640,7 +640,12 @@ public override void ForkStateReferences<T>(
LiteCollection<StateRefDoc> srcColl = _db.GetCollection<StateRefDoc>(srcCollId),
dstColl = _db.GetCollection<StateRefDoc>(dstCollId);

dstColl.InsertBulk(srcColl.Find(Query.LTE("BlockIndex", branchPoint.Index)));
Query srcQuery = Query.And(
Query.GT("BlockIndex", 0),
Query.LTE("BlockIndex", branchPoint.Index)
);
IEnumerable<StateRefDoc> srcStateRefs = srcColl.Find(srcQuery);
dstColl.InsertBulk(srcStateRefs);

if (!dstColl.Exists(_ => true) && CountIndex(sourceChainId) < 1)
{
Expand Down

0 comments on commit 6e9fca1

Please sign in to comment.