Пример #1
0
        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");
            }
        }
Пример #2
0
        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;
        }
Пример #3
0
        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
        }