internal static void ProcessValidatorStateDescriptor(StateDescriptor descriptor, Snapshot snapshot) { ECPoint pubkey = ECPoint.DecodePoint(descriptor.Key, ECCurve.Secp256r1); ValidatorState validator = snapshot.Validators.GetAndChange(pubkey, () => new ValidatorState(pubkey)); switch (descriptor.Field) { case "Registered": validator.Registered = BitConverter.ToBoolean(descriptor.Value, 0); break; } }
internal static void ProcessAccountStateDescriptor(StateDescriptor descriptor, Snapshot snapshot) { UInt160 hash = new UInt160(descriptor.Key); AccountState account = snapshot.Accounts.GetAndChange(hash, () => new AccountState(hash)); switch (descriptor.Field) { case "Votes": Fixed8 balance = account.GetBalance(GoverningToken.Hash); foreach (ECPoint pubkey in account.Votes) { ValidatorState validator = snapshot.Validators.GetAndChange(pubkey); validator.Votes -= balance; if (!validator.Registered && validator.Votes.Equals(Fixed8.Zero)) { snapshot.Validators.Delete(pubkey); } } ECPoint[] votes = descriptor.Value.AsSerializableArray <ECPoint>().Distinct().ToArray(); if (votes.Length != account.Votes.Length) { ValidatorsCountState count_state = snapshot.ValidatorsCount.GetAndChange(); if (account.Votes.Length > 0) { count_state.Votes[account.Votes.Length - 1] -= balance; } if (votes.Length > 0) { count_state.Votes[votes.Length - 1] += balance; } } account.Votes = votes; foreach (ECPoint pubkey in account.Votes) { snapshot.Validators.GetAndChange(pubkey, () => new ValidatorState(pubkey)).Votes += balance; } break; } }
private void Persist(Block block) { using (Snapshot snapshot = GetSnapshot()) { List <ApplicationExecuted> all_application_executed = new List <ApplicationExecuted>(); snapshot.PersistingBlock = block; snapshot.Blocks.Add(block.Hash, new BlockState { SystemFeeAmount = snapshot.GetSysFeeAmount(block.PrevHash) + (long)block.Transactions.Sum(p => p.SystemFee), TrimmedBlock = block.Trim() }); ushort m = 0; foreach (Transaction tx in block.Transactions) { snapshot.Transactions.Add(tx.Hash, new TransactionState { BlockIndex = block.Index, Transaction = tx }); snapshot.UnspentCoins.Add(tx.Hash, new UnspentCoinState { Items = Enumerable.Repeat(CoinState.Confirmed, tx.Outputs.Length).ToArray() }); foreach (TransactionOutput output in tx.Outputs) { AccountState account = snapshot.Accounts.GetAndChange(output.ScriptHash, () => new AccountState(output.ScriptHash)); if (account.Balances.ContainsKey(output.AssetId)) { account.Balances[output.AssetId] += output.Value; } else { account.Balances[output.AssetId] = output.Value; } if (output.AssetId.Equals(GoverningToken.Hash) && account.Votes.Length > 0) { foreach (ECPoint pubkey in account.Votes) { snapshot.Validators.GetAndChange(pubkey, () => new ValidatorState(pubkey)).Votes += output.Value; } snapshot.ValidatorsCount.GetAndChange().Votes[account.Votes.Length - 1] += output.Value; } } foreach (var group in tx.Inputs.GroupBy(p => p.PrevHash)) { TransactionState tx_prev = snapshot.Transactions[group.Key]; foreach (CoinReference input in group) { snapshot.UnspentCoins.GetAndChange(input.PrevHash).Items[input.PrevIndex] |= CoinState.Spent; TransactionOutput out_prev = tx_prev.Transaction.Outputs[input.PrevIndex]; AccountState account = snapshot.Accounts.GetAndChange(out_prev.ScriptHash); if (out_prev.AssetId.Equals(GoverningToken.Hash)) { snapshot.SpentCoins.GetAndChange(input.PrevHash, () => new SpentCoinState { TransactionHash = input.PrevHash, TransactionHeight = tx_prev.BlockIndex, Items = new Dictionary <ushort, uint>() }).Items.Add(input.PrevIndex, block.Index); if (account.Votes.Length > 0) { foreach (ECPoint pubkey in account.Votes) { ValidatorState validator = snapshot.Validators.GetAndChange(pubkey); validator.Votes -= out_prev.Value; if (!validator.Registered && validator.Votes.Equals(Fixed8.Zero)) { snapshot.Validators.Delete(pubkey); } } snapshot.ValidatorsCount.GetAndChange().Votes[account.Votes.Length - 1] -= out_prev.Value; } } account.Balances[out_prev.AssetId] -= out_prev.Value; } } List <ApplicationExecutionResult> execution_results = new List <ApplicationExecutionResult>(); switch (tx) { #pragma warning disable CS0612 case RegisterTransaction tx_register: snapshot.Assets.Add(tx.Hash, new AssetState { AssetId = tx_register.Hash, AssetType = tx_register.AssetType, Name = tx_register.Name, Amount = tx_register.Amount, Available = Fixed8.Zero, Precision = tx_register.Precision, Fee = Fixed8.Zero, FeeAddress = new UInt160(), Owner = tx_register.Owner, Admin = tx_register.Admin, Issuer = tx_register.Admin, Expiration = block.Index + 2 * 2000000, IsFrozen = false }); break; #pragma warning restore CS0612 case IssueTransaction _: foreach (TransactionResult result in tx.GetTransactionResults().Where(p => p.Amount < Fixed8.Zero)) { snapshot.Assets.GetAndChange(result.AssetId).Available -= result.Amount; } break; case ClaimTransaction _: foreach (CoinReference input in ((ClaimTransaction)tx).Claims) { if (snapshot.SpentCoins.TryGet(input.PrevHash)?.Items.Remove(input.PrevIndex) == true) { snapshot.SpentCoins.GetAndChange(input.PrevHash); } } break; #pragma warning disable CS0612 case EnrollmentTransaction tx_enrollment: snapshot.Validators.GetAndChange(tx_enrollment.PublicKey, () => new ValidatorState(tx_enrollment.PublicKey)).Registered = true; break; #pragma warning restore CS0612 case StateTransaction tx_state: foreach (StateDescriptor descriptor in tx_state.Descriptors) { switch (descriptor.Type) { case StateType.Account: ProcessAccountStateDescriptor(descriptor, snapshot); break; case StateType.Validator: ProcessValidatorStateDescriptor(descriptor, snapshot); break; } } break; #pragma warning disable CS0612 case PublishTransaction tx_publish: snapshot.Contracts.GetOrAdd(tx_publish.ScriptHash, () => new ContractState { Script = tx_publish.Script, ParameterList = tx_publish.ParameterList, ReturnType = tx_publish.ReturnType, ContractProperties = (ContractPropertyState)Convert.ToByte(tx_publish.NeedStorage), Name = tx_publish.Name, CodeVersion = tx_publish.CodeVersion, Author = tx_publish.Author, Email = tx_publish.Email, Description = tx_publish.Description }); break; #pragma warning restore CS0612 case InvocationTransaction tx_invocation: using (ApplicationEngine engine = new ApplicationEngine(TriggerType.Application, tx_invocation, snapshot.Clone(), tx_invocation.Gas)) { engine.LoadScript(tx_invocation.Script); engine.Execute(); if (!engine.State.HasFlag(VMState.FAULT)) { engine.Service.Commit(); } execution_results.Add(new ApplicationExecutionResult { Trigger = TriggerType.Application, ScriptHash = tx_invocation.Script.ToScriptHash(), VMState = engine.State, GasConsumed = engine.GasConsumed, Stack = engine.ResultStack.ToArray(), Notifications = engine.Service.Notifications.ToArray() }); } break; case DetainTransaction tx_detain: m++; switch (tx_detain.DetainState) { case DetainStatus.Freeze: var sh = tx_detain.ScriptHash; double r = Math.Pow(10, m.ToString().Length); var q = block.Index * r + m; AccountState acts = snapshot.Accounts.GetAndChange(sh, () => new AccountState(sh) { DetainState = tx_detain.DetainState, DetainExpire = block.Index, Magic = (uint)q }); var expire = acts.DetainExpire; if (expire < block.Index) { expire = block.Index; } expire += tx_detain.DetainDuration; acts.DetainExpire = expire; break; case DetainStatus.UnFreeze: var sh2 = tx_detain.ScriptHash; AccountState acts2 = snapshot.Accounts.GetAndChange(sh2, () => null); if (acts2.IsNotNull()) { if (acts2.DetainExpire < block.Index) { acts2.DetainState = DetainStatus.UnFreeze; acts2.DetainExpire = 0; } } break; } break; } if (execution_results.Count > 0) { ApplicationExecuted application_executed = new ApplicationExecuted { Transaction = tx, ExecutionResults = execution_results.ToArray() }; Context.System.EventStream.Publish(application_executed); all_application_executed.Add(application_executed); } } snapshot.BlockHashIndex.GetAndChange().Hash = block.Hash; snapshot.BlockHashIndex.GetAndChange().Index = block.Index; if (block.Index == header_index.Count) { header_index.Add(block.Hash); snapshot.HeaderHashIndex.GetAndChange().Hash = block.Hash; snapshot.HeaderHashIndex.GetAndChange().Index = block.Index; } foreach (IPersistencePlugin plugin in Plugin.PersistencePlugins) { plugin.OnPersist(snapshot, all_application_executed); } snapshot.Commit(); List <Exception> commitExceptions = null; foreach (IPersistencePlugin plugin in Plugin.PersistencePlugins) { try { plugin.OnCommit(snapshot); } catch (Exception ex) { if (plugin.ShouldThrowExceptionFromCommit(ex)) { if (commitExceptions == null) { commitExceptions = new List <Exception>(); } commitExceptions.Add(ex); } } } if (commitExceptions != null) { throw new AggregateException(commitExceptions); } } UpdateCurrentSnapshot(); OnPersistCompleted(block); }