public override IMicheline Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { Stack <IMicheline> stack = new(); IMicheline node, top; MichelinePrim prim; string prop; start: switch (reader.TokenType) { case JsonTokenType.StartObject: reader.Read(); if (reader.TokenType != JsonTokenType.PropertyName) { throw new FormatException("Empty Micheline node"); } prop = reader.GetString(); reader.Read(); switch (prop) { case "prim": stack.Push(new MichelinePrim { Prim = PrimTypeConverter.ParsePrim(reader.GetString()) }); reader.Read(); goto start; case "args": stack.Push(new MichelinePrim()); if (reader.TokenType == JsonTokenType.StartArray) { reader.Read(); if (reader.TokenType != JsonTokenType.EndArray) { stack.Push(new MichelineArray(2)); goto start; } } else if (reader.TokenType != JsonTokenType.Null) { throw new FormatException("Invalid prim args"); } reader.Read(); goto start; case "annots": List <IAnnotation> annots = null; if (reader.TokenType == JsonTokenType.StartArray) { reader.Read(); if (reader.TokenType == JsonTokenType.String) { annots = new(2); annots.Add(AnnotationConverter.ParseAnnotation(reader.GetString())); reader.Read(); while (reader.TokenType == JsonTokenType.String) { annots.Add(AnnotationConverter.ParseAnnotation(reader.GetString())); reader.Read(); } } if (reader.TokenType != JsonTokenType.EndArray) { throw new FormatException("Invalid prim annotation"); } } else if (reader.TokenType != JsonTokenType.Null) { throw new FormatException("Invalid prim annots"); } stack.Push(new MichelinePrim { Annots = annots }); reader.Read(); goto start; case "bytes": if (reader.TokenType != JsonTokenType.String) { throw new FormatException("Invalid Micheline bytes node"); } node = new MichelineBytes(Hex.Parse(reader.GetString())); break; case "string": if (reader.TokenType != JsonTokenType.String) { throw new FormatException("Invalid Micheline string node"); } node = new MichelineString(reader.GetString()); break; case "int": if (reader.TokenType != JsonTokenType.String) { throw new FormatException("Invalid Micheline int node"); } node = new MichelineInt(BigInteger.Parse(reader.GetString())); break; default: throw new FormatException("Invalid Micheline node"); } reader.Read(); if (reader.TokenType != JsonTokenType.EndObject) { throw new FormatException($"Invalid Micheline {node.Type} node"); } goto endNode; case JsonTokenType.PropertyName: prim = (MichelinePrim)stack.Peek(); prop = reader.GetString(); reader.Read(); switch (prop) { case "prim": prim.Prim = PrimTypeConverter.ParsePrim(reader.GetString()); reader.Read(); goto start; case "args": if (reader.TokenType == JsonTokenType.StartArray) { reader.Read(); if (reader.TokenType != JsonTokenType.EndArray) { stack.Push(new MichelineArray(2)); goto start; } } else if (reader.TokenType != JsonTokenType.Null) { throw new FormatException("Invalid prim args"); } reader.Read(); goto start; case "annots": List <IAnnotation> annots = null; if (reader.TokenType == JsonTokenType.StartArray) { reader.Read(); if (reader.TokenType == JsonTokenType.String) { annots = new(2); annots.Add(AnnotationConverter.ParseAnnotation(reader.GetString())); reader.Read(); while (reader.TokenType == JsonTokenType.String) { annots.Add(AnnotationConverter.ParseAnnotation(reader.GetString())); reader.Read(); } } if (reader.TokenType != JsonTokenType.EndArray) { throw new FormatException("Invalid prim annotation"); } } else if (reader.TokenType != JsonTokenType.Null) { throw new FormatException("Invalid prim annots"); } prim.Annots = annots; reader.Read(); goto start; default: throw new FormatException(); } case JsonTokenType.EndObject: node = stack.Pop(); endNode: if (stack.Count == 0) { return(node); } ((MichelineArray)stack.Peek()).Add(node); reader.Read(); goto start; case JsonTokenType.StartArray: stack.Push(new MichelineArray()); reader.Read(); goto start; case JsonTokenType.EndArray: node = stack.Pop(); if (stack.Count == 0) { return(node); } top = stack.Peek(); if (top is MichelinePrim pr) { pr.Args = (MichelineArray)node; } else { ((MichelineArray)top).Add(node); } reader.Read(); goto start; default: throw new FormatException("Invalid Micheline format"); } }
static IMicheline ReadFlat(BinaryReader reader) { Stack <IMicheline> stack = new(); IMicheline node, top; MichelinePrim prim; MichelineArray arr; int tag, cnt, args, annots; start: tag = reader.ReadByte(); if (tag >= 0x80) { prim = new() { Prim = (PrimType)reader.ReadByte() }; annots = tag & 0x0F; if (annots > 0) { if (annots == 0x0F) { annots = reader.Read7BitInt(); } prim.Annots = new(annots); } args = (tag & 0x70) >> 4; if (args > 0) { if (args == 0x07) { args = reader.Read7BitInt(); } prim.Args = new(args); stack.Push(prim); goto start; } if (prim.Annots != null) { ReadAnnots(reader, prim); } node = prim; } else { cnt = tag & 0x1F; if (cnt == 0x1F) { cnt = reader.Read7BitInt(); } switch ((MichelineType)(tag & 0xE0)) { case MichelineType.Array: node = new MichelineArray(cnt); if (cnt > 0) { stack.Push(node); goto start; } break; case MichelineType.Bytes: node = new MichelineBytes(reader.ReadBytes(cnt)); break; case MichelineType.Int: node = new MichelineInt(new BigInteger(reader.ReadBytes(cnt))); break; case MichelineType.String: node = new MichelineString(Utf8.Convert(reader.ReadBytes(cnt))); break; default: throw new FormatException("Invalid micheline tag"); } } finish: if (stack.Count == 0) { return(node); } top = stack.Peek(); if (top is MichelinePrim p) { p.Args.Add(node); if (p.Args.Count < p.Args.Capacity) { goto start; } if (p.Annots != null) { ReadAnnots(reader, p); } } else { arr = (MichelineArray)top; arr.Add(node); if (arr.Count < arr.Capacity) { goto start; } } node = stack.Pop(); goto finish; }
async Task OriginateContract(Block block, string address) { var rawContract = await Proto.Rpc.GetContractAsync(block.Level, address); #region contract var contract = new Contract { Id = Cache.AppState.NextAccountId(), FirstBlock = block, Address = address, Balance = rawContract.RequiredInt64("balance"), Creator = await Cache.Accounts.GetAsync(NullAddress.Address), Type = AccountType.Contract, Kind = ContractKind.SmartContract, MigrationsCount = 1, }; Db.TryAttach(contract.Creator); contract.Creator.ContractsCount++; Db.Accounts.Add(contract); #endregion #region script var code = Micheline.FromJson(rawContract.Required("script").Required("code")) as MichelineArray; var micheParameter = code.First(x => x is MichelinePrim p && p.Prim == PrimType.parameter); var micheStorage = code.First(x => x is MichelinePrim p && p.Prim == PrimType.storage); var micheCode = code.First(x => x is MichelinePrim p && p.Prim == PrimType.code); var micheViews = code.Where(x => x is MichelinePrim p && p.Prim == PrimType.view); var script = new Script { Id = Cache.AppState.NextScriptId(), Level = block.Level, ContractId = contract.Id, ParameterSchema = micheParameter.ToBytes(), StorageSchema = micheStorage.ToBytes(), CodeSchema = micheCode.ToBytes(), Views = micheViews.Any() ? micheViews.Select(x => x.ToBytes()).ToArray() : null, Current = true }; var viewsBytes = script.Views? .OrderBy(x => x, new BytesComparer()) .SelectMany(x => x) .ToArray() ?? Array.Empty <byte>(); var typeSchema = script.ParameterSchema.Concat(script.StorageSchema).Concat(viewsBytes); var fullSchema = typeSchema.Concat(script.CodeSchema); contract.TypeHash = script.TypeHash = Script.GetHash(typeSchema); contract.CodeHash = script.CodeHash = Script.GetHash(fullSchema); if (script.Schema.IsFA1()) { if (script.Schema.IsFA12()) { contract.Tags |= ContractTags.FA12; } contract.Tags |= ContractTags.FA1; contract.Kind = ContractKind.Asset; } if (script.Schema.IsFA2()) { contract.Tags |= ContractTags.FA2; contract.Kind = ContractKind.Asset; } Db.Scripts.Add(script); #endregion #region storage var storageValue = Micheline.FromJson(rawContract.Required("script").Required("storage")); var storage = new Storage { Id = Cache.AppState.NextStorageId(), Level = block.Level, ContractId = contract.Id, RawValue = script.Schema.OptimizeStorage(storageValue, false).ToBytes(), JsonValue = script.Schema.HumanizeStorage(storageValue), Current = true }; Db.Storages.Add(storage); #endregion #region migration var migration = new MigrationOperation { Id = Cache.AppState.NextOperationId(), Block = block, Level = block.Level, Timestamp = block.Timestamp, Kind = MigrationKind.Origination, Account = contract, BalanceChange = contract.Balance, Script = script, Storage = storage, }; script.MigrationId = migration.Id; storage.MigrationId = migration.Id; block.Events |= BlockEvents.SmartContracts; block.Operations |= Operations.Migrations; var state = Cache.AppState.Get(); state.MigrationOpsCount++; var statistics = await Cache.Statistics.GetAsync(state.Level); statistics.TotalCreated += contract.Balance; Db.MigrationOps.Add(migration); #endregion #region bigmaps var storageScript = new ContractStorage(micheStorage); var storageTree = storageScript.Schema.ToTreeView(storageValue); var bigmaps = storageTree.Nodes() .Where(x => x.Schema is BigMapSchema) .Select(x => (x, x.Schema as BigMapSchema, (int)(x.Value as MichelineInt).Value)); foreach (var(bigmap, schema, ptr) in bigmaps) { block.Events |= BlockEvents.Bigmaps; migration.BigMapUpdates = (migration.BigMapUpdates ?? 0) + 1; Db.BigMapUpdates.Add(new BigMapUpdate { Id = Cache.AppState.NextBigMapUpdateId(), Action = BigMapAction.Allocate, BigMapPtr = ptr, Level = block.Level, MigrationId = migration.Id }); var allocated = new BigMap { Id = Cache.AppState.NextBigMapId(), Ptr = ptr, ContractId = contract.Id, StoragePath = bigmap.Path, KeyType = schema.Key.ToMicheline().ToBytes(), ValueType = schema.Value.ToMicheline().ToBytes(), Active = true, FirstLevel = block.Level, LastLevel = block.Level, ActiveKeys = 0, TotalKeys = 0, Updates = 1, Tags = BigMaps.GetTags(bigmap) }; Db.BigMaps.Add(allocated); if (address == LiquidityToken && allocated.StoragePath == "tokens") { var rawKey = new MichelineString(NullAddress.Address); var rawValue = new MichelineInt(100); allocated.ActiveKeys++; allocated.TotalKeys++; allocated.Updates++; var key = new BigMapKey { Id = Cache.AppState.NextBigMapKeyId(), Active = true, BigMapPtr = ptr, FirstLevel = block.Level, LastLevel = block.Level, JsonKey = schema.Key.Humanize(rawKey), JsonValue = schema.Value.Humanize(rawValue), RawKey = schema.Key.Optimize(rawKey).ToBytes(), RawValue = schema.Value.Optimize(rawValue).ToBytes(), KeyHash = schema.GetKeyHash(rawKey), Updates = 1 }; Db.BigMapKeys.Add(key); migration.BigMapUpdates++; Db.BigMapUpdates.Add(new BigMapUpdate { Id = Cache.AppState.NextBigMapUpdateId(), Action = BigMapAction.AddKey, BigMapKeyId = key.Id, BigMapPtr = key.BigMapPtr, JsonValue = key.JsonValue, RawValue = key.RawValue, Level = key.LastLevel, MigrationId = migration.Id }); } } #endregion }