public override void SetBlockStates( HashDigest <SHA256> blockHash, AddressStateMap states ) { var statesFile = new FileInfo(GetStatesPath(blockHash)); if (!statesFile.Directory.Exists) { statesFile.Directory.Create(); } using (Stream stream = statesFile.OpenWrite()) { var formatter = new BinaryFormatter(); formatter.Serialize(stream, states); } }
public AddressStateMap GetStates( IEnumerable <Address> addresses, HashDigest <SHA256>?offset = null) { _rwlock.EnterReadLock(); try { if (offset == null) { offset = Store.IndexBlockHash(Id.ToString(), -1); } } finally { _rwlock.ExitReadLock(); } var states = new AddressStateMap(); while (offset != null) { states = (AddressStateMap)states.SetItems( Store.GetBlockStates(offset.Value) .Where( kv => addresses.Contains(kv.Key) && !states.ContainsKey(kv.Key)) ); if (states.Keys.SequenceEqual(addresses)) { break; } offset = Blocks[offset.Value].PreviousHash; } return(states); }
public void StoreBlockState() { Assert.Empty(_fx.Store.GetBlockStates(_fx.Hash1)); AddressStateMap states = new AddressStateMap( new Dictionary <Address, object>() { [_fx.Address1] = new Dictionary <string, int>() { { "a", 1 }, }, [_fx.Address2] = new Dictionary <string, int>() { { "b", 2 }, }, }.ToImmutableDictionary() ); _fx.Store.SetBlockStates(_fx.Hash1, states); AddressStateMap actual = _fx.Store.GetBlockStates(_fx.Hash1); Assert.Equal(states[_fx.Address1], actual[_fx.Address1]); Assert.Equal(states[_fx.Address2], actual[_fx.Address2]); }
public void BlockState() { Assert.Null(Fx.Store.GetBlockStates(Fx.Hash1)); AddressStateMap states = new AddressStateMap( new Dictionary <Address, IValue>() { [Fx.Address1] = new Bencodex.Types.Dictionary(new Dictionary <IKey, IValue> { { (Text)"a", (Integer)1 }, }), [Fx.Address2] = new Bencodex.Types.Dictionary(new Dictionary <IKey, IValue> { { (Text)"b", (Integer)2 }, }), }.ToImmutableDictionary() ); Fx.Store.SetBlockStates(Fx.Hash1, states); AddressStateMap actual = Fx.Store.GetBlockStates(Fx.Hash1); Assert.Equal(states[Fx.Address1], actual[Fx.Address1]); Assert.Equal(states[Fx.Address2], actual[Fx.Address2]); }
private void EvaluateActions(Block <T> block) { HashDigest <SHA256>?prevHash = block.PreviousHash; var states = new AddressStateMap(); int seed = BitConverter.ToInt32(block.Hash.ToByteArray(), 0); foreach (Transaction <T> tx in block.Transactions) { int txSeed = seed ^ BitConverter.ToInt32(tx.Signature, 0); foreach (T action in tx.Actions) { IEnumerable <Address> requestedAddresses = action.RequestStates(tx.Sender, tx.Recipient); AddressStateMap requested = GetStates( requestedAddresses.Except(states.Keys), prevHash); states = (AddressStateMap)requested.SetItems(states); var prevState = new AddressStateMap( requestedAddresses .Where(states.ContainsKey) .ToImmutableDictionary(a => a, a => states[a])); var context = new ActionContext( @from: tx.Sender, to: tx.Recipient, blockIndex: block.Index, previousStates: prevState, randomSeed: unchecked (txSeed++) ); AddressStateMap changes = action.Execute(context); states = (AddressStateMap)states.SetItems(changes); } } Store.SetBlockStates(Id.ToString(), block.Hash, states); }
/// <summary> /// Gets the state of the given <paramref name="addresses"/> in the /// <see cref="BlockChain{T}"/> from <paramref name="offset"/>. /// </summary> /// <param name="addresses">The list of <see cref="Address"/>es to get /// their states.</param> /// <param name="offset">The <see cref="HashDigest{T}"/> of the block to /// start finding the state. It will be The tip of the /// <see cref="BlockChain{T}"/> if it is <c>null</c>.</param> /// <param name="completeStates">When the <see cref="BlockChain{T}"/> /// instance does not contain states dirty of the block which lastly /// updated states of a requested address, this option makes /// the incomplete states calculated and filled on the fly. /// If this option is turned off (which is default) this method throws /// <see cref="IncompleteBlockStatesException"/> instead /// for the same situation. /// Just-in-time calculation of states could take a long time so that /// the overall latency of an application may rise.</param> /// <returns>The <see cref="AddressStateMap"/> of given /// <paramref name="addresses"/>.</returns> /// <exception cref="IncompleteBlockStatesException">Thrown when /// the <see cref="BlockChain{T}"/> instance does not contain /// states dirty of the block which lastly updated states of a requested /// address, because actions in the block have never been executed. /// If <paramref name="completeStates"/> option is turned on /// this exception is not thrown and incomplete states are calculated /// and filled on the fly instead. /// </exception> public AddressStateMap GetStates( IEnumerable <Address> addresses, HashDigest <SHA256>?offset = null, bool completeStates = false ) { _rwlock.EnterReadLock(); try { if (offset == null) { offset = Store.IndexBlockHash(Id, -1); } } finally { _rwlock.ExitReadLock(); } var states = new AddressStateMap(); if (offset == null) { return(states); } Block <T> block = Blocks[offset.Value]; ImmutableHashSet <Address> requestedAddresses = addresses.ToImmutableHashSet(); var stateReferences = new HashSet <Tuple <HashDigest <SHA256>, long> >(); foreach (var address in requestedAddresses) { Tuple <HashDigest <SHA256>, long> sr; _rwlock.EnterReadLock(); try { sr = Store.LookupStateReference(Id, address, block); } finally { _rwlock.ExitReadLock(); } if (!(sr is null)) { stateReferences.Add(sr); } } IEnumerable <HashDigest <SHA256> > hashValues = stateReferences .OrderByDescending(sr => sr.Item2) .Select(sr => sr.Item1); foreach (var hashValue in hashValues) { AddressStateMap blockStates = Store.GetBlockStates(hashValue); if (blockStates is null) { if (completeStates) { // Calculates and fills the incomplete states // on the fly. foreach (Block <T> b in this) { if (!(Store.GetBlockStates(b.Hash) is null)) { continue; } List <ActionEvaluation> evaluations = b.Evaluate( DateTimeOffset.UtcNow, a => GetStates( new[] { a }, b.PreviousHash ).GetValueOrDefault(a) ).ToList(); if (Policy.BlockAction is IAction) { evaluations.Add(EvaluateBlockAction(b, evaluations)); } _rwlock.EnterWriteLock(); try { SetStates(b, evaluations, buildStateReferences: false); } finally { _rwlock.ExitWriteLock(); } } blockStates = Store.GetBlockStates(hashValue); if (blockStates is null) { throw new NullReferenceException(); } } else { throw new IncompleteBlockStatesException(hashValue); } } states = (AddressStateMap)states.SetItems( blockStates.Where(kv => requestedAddresses.Contains(kv.Key) && !states.ContainsKey(kv.Key) ) ); } return(states); }
public void CanProcessActions() { var actions1 = new List <BaseAction>() { new Attack() { Weapon = "sword", Target = "goblin", }, new Attack() { Weapon = "sword", Target = "orc", }, new Attack() { Weapon = "staff", Target = "goblin", }, }; Transaction <BaseAction> tx1 = Transaction <BaseAction> .Make( new PrivateKey(), _fx.Address1, actions1, DateTimeOffset.UtcNow ); _blockChain.StageTransactions(new HashSet <Transaction <BaseAction> > { tx1 }); _blockChain.MineBlock(_fx.Address1); AddressStateMap states = _blockChain.GetStates(new List <Address> { _fx.Address1 }); Assert.NotEmpty(states); var result = (BattleResult)states[_fx.Address1]; Assert.Contains("sword", result.UsedWeapons); Assert.Contains("staff", result.UsedWeapons); Assert.Contains("orc", result.Targets); Assert.Contains("goblin", result.Targets); var actions2 = new List <BaseAction>() { new Attack() { Weapon = "bow", Target = "goblin", }, }; Transaction <BaseAction> tx2 = Transaction <BaseAction> .Make( new PrivateKey(), _fx.Address1, actions2, DateTimeOffset.UtcNow ); _blockChain.StageTransactions(new HashSet <Transaction <BaseAction> > { tx2 }); _blockChain.MineBlock(_fx.Address1); states = _blockChain.GetStates(new List <Address> { _fx.Address1 }); result = (BattleResult)states[_fx.Address1]; Assert.Contains("bow", result.UsedWeapons); }
public abstract void SetBlockStates( string @namespace, HashDigest <SHA256> blockHash, AddressStateMap states );
public abstract AddressStateMap Execute(Address from, Address to, AddressStateMap states);
public void ProcessActions() { var actions1 = new List <PolymorphicAction <BaseAction> >() { new Attack { Weapon = "sword", Target = "goblin", TargetAddress = _fx.Address1, }, new Attack { Weapon = "sword", Target = "orc", TargetAddress = _fx.Address1, }, new Attack { Weapon = "staff", Target = "goblin", TargetAddress = _fx.Address1, }, }; var tx1 = Transaction <PolymorphicAction <BaseAction> > .Create( new PrivateKey(), actions1 ); var chain = new BlockChain <PolymorphicAction <BaseAction> >( new BlockPolicy <PolymorphicAction <BaseAction> >(), _fx.Store ); chain.StageTransactions( new HashSet <Transaction <PolymorphicAction <BaseAction> > > { tx1 } ); var lastBlock = chain.MineBlock(_fx.Address1); AddressStateMap states = chain.GetStates( new List <Address> { _fx.Address1 } ); Assert.NotEmpty(states); var result = (BattleResult)states[_fx.Address1]; Assert.Contains("sword", result.UsedWeapons); Assert.Contains("staff", result.UsedWeapons); Assert.Contains("orc", result.Targets); Assert.Contains("goblin", result.Targets); PolymorphicAction <BaseAction>[] actions2 = { new Attack { Weapon = "bow", Target = "goblin", TargetAddress = _fx.Address1, }, }; var tx2 = Transaction <PolymorphicAction <BaseAction> > .Create( new PrivateKey(), actions2 ); chain.StageTransactions( new HashSet <Transaction <PolymorphicAction <BaseAction> > > { tx2 } ); chain.MineBlock(_fx.Address1); states = chain.GetStates(new List <Address> { _fx.Address1 }); result = (BattleResult)states[_fx.Address1]; Assert.Contains("bow", result.UsedWeapons); }
public abstract void SetBlockStates( HashDigest <SHA256> blockHash, AddressStateMap states );
public override AddressStateMap Execute(Address from, Address to, AddressStateMap states) { throw new NotImplementedException(); }
/// <summary> /// Gets the state of the given <paramref name="address"/> in the /// <see cref="BlockChain{T}"/> from <paramref name="offset"/>. /// </summary> /// <param name="address">An <see cref="Address"/> to get /// the states of.</param> /// <param name="offset">The <see cref="HashDigest{T}"/> of the block to /// start finding the state. It will be The tip of the /// <see cref="BlockChain{T}"/> if it is <c>null</c>.</param> /// <param name="completeStates">When the <see cref="BlockChain{T}"/> /// instance does not contain states dirty of the block which lastly /// updated states of a requested address, this option makes /// the incomplete states calculated and filled on the fly. /// If this option is turned off (which is default) this method throws /// <see cref="IncompleteBlockStatesException"/> instead /// for the same situation. /// Just-in-time calculation of states could take a long time so that /// the overall latency of an application may rise.</param> /// <returns>The <see cref="AddressStateMap"/> of given /// <paramref name="address"/>.</returns> /// <exception cref="IncompleteBlockStatesException">Thrown when /// the <see cref="BlockChain{T}"/> instance does not contain /// states dirty of the block which lastly updated states of a requested /// address, because actions in the block have never been executed. /// If <paramref name="completeStates"/> option is turned on /// this exception is not thrown and incomplete states are calculated /// and filled on the fly instead. /// </exception> public AddressStateMap GetState( Address address, HashDigest <SHA256>?offset = null, bool completeStates = false ) { _rwlock.EnterReadLock(); try { if (offset == null) { offset = Store.IndexBlockHash(Id, -1); } } finally { _rwlock.ExitReadLock(); } var states = new AddressStateMap(); if (offset == null) { return(states); } Block <T> block = Blocks[offset.Value]; Tuple <HashDigest <SHA256>, long> stateReference; _rwlock.EnterReadLock(); try { stateReference = Store.LookupStateReference(Id, address, block); } finally { _rwlock.ExitReadLock(); } if (stateReference is null) { return(states); } HashDigest <SHA256> hashValue = stateReference.Item1; AddressStateMap blockStates = Store.GetBlockStates(hashValue); if (blockStates is null) { if (completeStates) { // Calculates and fills the incomplete states // on the fly. foreach (Block <T> b in this) { if (!(Store.GetBlockStates(b.Hash) is null)) { continue; } List <ActionEvaluation> evaluations = b.Evaluate( DateTimeOffset.UtcNow, a => GetState( a, b.PreviousHash ).GetValueOrDefault(a) ).ToList(); if (Policy.BlockAction is IAction) { evaluations.Add(EvaluateBlockAction(b, evaluations)); } _rwlock.EnterWriteLock(); try { SetStates(b, evaluations, buildStateReferences: false); } finally { _rwlock.ExitWriteLock(); } } blockStates = Store.GetBlockStates(hashValue); if (blockStates is null) { throw new NullReferenceException(); } } else { throw new IncompleteBlockStatesException(hashValue); } } states = (AddressStateMap)states.SetItems( blockStates.Where(kv => address.Equals(kv.Key)) ); return(states); }
/// <summary> /// Gets the state of the given <paramref name="address"/> in the /// <see cref="BlockChain{T}"/> from <paramref name="offset"/>. /// </summary> /// <param name="address">An <see cref="Address"/> to get /// the states of.</param> /// <param name="offset">The <see cref="HashDigest{T}"/> of the block to /// start finding the state. It will be The tip of the /// <see cref="BlockChain{T}"/> if it is <c>null</c>.</param> /// <param name="completeStates">When the <see cref="BlockChain{T}"/> /// instance does not contain states dirty of the block which lastly /// updated states of a requested address, this option makes /// the incomplete states calculated and filled on the fly. /// If this option is turned off (which is default) this method throws /// <see cref="IncompleteBlockStatesException"/> instead /// for the same situation. /// Just-in-time calculation of states could take a long time so that /// the overall latency of an application may rise.</param> /// <returns>The <see cref="AddressStateMap"/> of given /// <paramref name="address"/>.</returns> /// <exception cref="IncompleteBlockStatesException">Thrown when /// the <see cref="BlockChain{T}"/> instance does not contain /// states dirty of the block which lastly updated states of a requested /// address, because actions in the block have never been executed. /// If <paramref name="completeStates"/> option is turned on /// this exception is not thrown and incomplete states are calculated /// and filled on the fly instead. /// </exception> public AddressStateMap GetState( Address address, HashDigest <SHA256>?offset = null, bool completeStates = false ) { _rwlock.EnterReadLock(); try { if (offset == null) { offset = Store.IndexBlockHash(Id, -1); } } finally { _rwlock.ExitReadLock(); } var states = new AddressStateMap(); if (offset == null) { return(states); } Block <T> block = this[offset.Value]; Tuple <HashDigest <SHA256>, long> stateReference; _rwlock.EnterReadLock(); try { stateReference = Store.LookupStateReference(Id, address, block); } finally { _rwlock.ExitReadLock(); } if (stateReference is null) { return(states); } HashDigest <SHA256> hashValue = stateReference.Item1; AddressStateMap blockStates = Store.GetBlockStates(hashValue); if (blockStates is null) { if (completeStates) { // Calculates and fills the incomplete states // on the fly. foreach (HashDigest <SHA256> hash in BlockHashes) { Block <T> b = this[hash]; if (!(Store.GetBlockStates(b.Hash) is null)) { continue; } IReadOnlyList <ActionEvaluation> evaluations = EvaluateActions(b); _rwlock.EnterWriteLock(); try { SetStates(b, evaluations, buildStateReferences: false); } finally { _rwlock.ExitWriteLock(); } } blockStates = Store.GetBlockStates(hashValue); if (blockStates is null) { throw new NullReferenceException(); } } else { throw new IncompleteBlockStatesException(hashValue); } } states = (AddressStateMap)states.SetItems( blockStates.Where(kv => address.Equals(kv.Key)) ); return(states); }
public override AddressStateMap Execute(Address sender, Address recipient, AddressStateMap requestedStates) { throw new NotImplementedException(); }