NEO looks at digital assets from source code analysis

0x00 Introduction

Is Bitcoin a Bubble? Maybe. After all, except for frying, this thing feels painful. But it is very annoying to compare the Bitcoin bubble with the tulip bubble. What the heck is a tulip? It’s been so long for a year and a few days, and the bubble hasn’t burst yet. Bitcoin is different. Not only is the coin produced by each block unique, but each coin also has its own unique history. There will be more than 20 million bitcoins in the world, but the 50 coins in the genesis block of Satoshi Nakamoto cannot replace anything. Having said that, if the tulip flowers that opened during the tulip bubble period can be preserved to the present, the value will be absolutely leveraged. But the question is, what exactly defines the total amount of cryptocurrencies, and what exactly is the "coin" we have? As the third blog of NEO source code analysis Hillie, this article will analyze the source code of NEO asset part from the perspective of source code. Links to the first two articles:

Note: In the following article, the English abbreviation "NEO" refers to the management token "NEO Coin" used in the NEO network, and the English abbreviation "GAS" refers to the fuel token "NEOGas" in the NEO network.

0x01 Total Assets

Before explaining the specific assets in the NEO network, we need to explain the class RegisterTransaction used to register new assets in the NEO network. This class is used to register new assets, which means that anyone can publish new assets based on the NEO network. RegisterTransaction inherits from Transaction, which means that the process of publishing assets is also a transaction process, and the transaction information will be recorded in the block to ensure that the data cannot be tampered with. The key fields in RegisterTransaction are as follows:

  • AssetType // asset class
  • Name // asset name
  • Amount // total amount of tokens
  • Precision //Token precision
  • Owner // Issuer's public key
  • Admin // Asset manager's contract hash
  • Attributes // Transaction characteristics: usage and its data In addition, it is very expensive to release a new asset to the NEO network, requiring 5000 GAS, and according to the current market price, it requires about 1.5 million RMB. Even in the test network, the GAS given to me by the official handout is only 5000 GAS.

There are two official assets in the NEO network, one is the management token NEO, which serves as a certificate for managing the NEO network, and the other is the fuel currency GAS, which has a function similar to that of BitCoin in the Bitcoin network. Because the consensus strategy of the NEO network adopts the voting mechanism, the more people who hold NEO, the greater the voting power, and the more chance they have to become members of the NEO network. Members preside over the daily operation of the NEO network, generate new blocks, and receive newly generated GAS as rewards. Other than that, NEO has no other use. GAS is used to pay for daily transactions and contract execution fees in the blockchain network. At the beginning of the creation of the NEO network, the total amount of NEO is determined and written into the blockchain and cannot be changed. The code for creating NEO management tokens is in the BlockChain.cs file: Source code location: neo/Core/BlockChain.cs

public static readonly RegisterTransaction GoverningToken = new RegisterTransaction
        {
            AssetType = AssetType.GoverningToken,
            Name = "[{\"lang\":\"zh-CN\",\"name\":\"小蚁股\"},{\"lang\":\"en\",\"name\":\"AntShare\"}]",
            Amount = Fixed8.FromDecimal(100000000),  /* NEO管理代币总量一亿份 */
            Precision = 0,   /* 小数点精度为0,意味着NEO最小单位为1, 不可再分 */
            Owner = ECCurve.Secp256r1.Infinity,
            Admin = (new[] { (byte)OpCode.PUSHT }).ToScriptHash(),
            Attributes = new TransactionAttribute[0],
            Inputs = new CoinReference[0],
            Outputs = new TransactionOutput[0],
            Scripts = new Witness[0]
        };

It can be seen from the code that at the beginning, the total amount of NEO is hard-coded into the blockchain, and does not involve complex calculations. In the same way, below the code for registering NEO assets is the code for registering GAS assets:

        public static readonly RegisterTransaction UtilityToken = new RegisterTransaction
        {
            AssetType = AssetType.UtilityToken,
            Name = "[{\"lang\":\"zh-CN\",\"name\":\"小蚁币\"},{\"lang\":\"en\",\"name\":\"AntCoin\"}]",
            Amount = Fixed8.FromDecimal(GenerationAmount.Sum(p => p) * DecrementInterval), 
            Precision = 8, //精度为小数点后8位
            Owner = ECCurve.Secp256r1.Infinity,
            Admin = (new[] { (byte)OpCode.PUSHF }).ToScriptHash(),
            Attributes = new TransactionAttribute[0],
            Inputs = new CoinReference[0],
            Outputs = new TransactionOutput[0],
            Scripts = new Witness[0]
        };

It can be seen that the total amount of GAS is calculated. The GenerationAmount array defines the amount of GAS that is rewarded for each block generated over time, and the DecrementInterval is the decay rate of the amount of generated GAS: every 2 million blocks are generated, The newly generated block reward GAS is attenuated by the value in the GenerationAmount array. I did a quick calculation with a calculator, and the total amount is also 100 million, which is consistent with the definition in the white paper.

But here comes the problem. To release a new asset, it needs to consume 5000 GAS, but if GAS is not released, it is impossible for GAS to exist in the NEO network. Publishing GAS requires GAS, which is a paradox. Of course, this is a paradox in my eyes, not in the eyes of Core developers. The registration of NEO and GAS assets is directly hard-coded in the genesis block as part of the genesis block transaction. Then, with the nodes of the new network, they are synchronized to all parts of the world. The hard-coded transactions in the Genesis Block are as follows: Source address: neo/Core/BlockChain.cs/GenesisBlock

        Transactions = new Transaction[]
            {
                new MinerTransaction // 创建矿工交易
                {
                    Nonce = 2083236893,
                    Attributes = new TransactionAttribute[0],
                    Inputs = new CoinReference[0],
                    Outputs = new TransactionOutput[0],
                    Scripts = new Witness[0]
                },
                GoverningToken,  // 发布NEO
                UtilityToken,         // 发布GAS
                new IssueTransaction // 用于分发资产的特殊交易
                {
                    // 代码省略
                }
            }

0x02 Asset distribution

After new asset types are created, where do those assets go? How did you get the assets you created yourself? In section 0x01, I omitted the details of the IssueTransaction transaction in the genesis block generation code, because this part needs to be explained in detail, and the detailed code is pasted below:

Source address: neo/Core/BlockChain.cs/GenesisBlock

    new IssueTransaction
                {
                    Attributes = new TransactionAttribute[0],  // 交易属性
                    Inputs = new CoinReference[0],  
                    Outputs = new[]  //
                    {
                        new TransactionOutput
                        {
                            AssetId = GoverningToken.Hash,
                            Value = GoverningToken.Amount, // 直接分发全部NEO
                            ScriptHash = Contract.CreateMultiSigRedeemScript(StandbyValidators.Length / 2 + 1, StandbyValidators).ToScriptHash() 
                        }
                    },
                    Scripts = new[]
                    {
                       // 代码省略
                    }
                }

IssueTransaction inherits from Transaction and is a special transaction for distributing assets. The biggest peculiarity of this kind of transaction is that you need to pay a system transaction fee, which is defined in the protocol.json file:

Source code location: neo/protocol.json

       "SystemFee": {
              "EnrollmentTransaction": 1000,
              "IssueTransaction": 500,
              "PublishTransaction": 500,
              "RegisterTransaction": 10000
    }

In the IssueTransaction transaction in the genesis block, all NEO is directly distributed. What does this mean? Meaning, if you're one of the StandbyValidators, you've now achieved dozens of small goals in life.

The distribution of GAS is relatively complicated, because GAS needs to be mined, and there is a decay period. Mining GAS involves the consensus process of the NEO network. Students who are interested in the consensus algorithm of the NEO network can read my other blog post "NEO Sees Consensus Protocol from Source Code Analysis" . At the beginning of each view cycle, the speaker adds miner transactions and signs the locally cached transaction information and broadcasts it to the members. The members verify, and after the number of members who pass the verification is legal, the speaker creates a new block. The calculation of the amount of GAS rewarded for each block is performed when the miner transaction is created:

Source code location: neo/Consensus/ConsensusService.cs/CreateMinerTransaction

Fixed8 amount_netfee = Block.CalculateNetFee(transactions); // 获取手续费(in-out-sysfee)
TransactionOutput[] outputs = amount_netfee == Fixed8.Zero ? new TransactionOutput[0] : new[] { new TransactionOutput
{
          AssetId = Blockchain.UtilityToken.Hash,
          Value = amount_netfee,
          ScriptHash = wallet.GetChangeAddress()
 } };

It can be seen that the CalculateNetFee method of Block is called here to calculate the fee that the current block should get, and the reward of the current block also naturally belongs to the account that generated the current block.

0x03 Account balance

I have talked so much before, but I still haven't made a concept clear----"{'CH':'Coin','EN':'Coin'}", what exactly is a coin? What exactly is the balance shown in our NEO wallet? In the NEO network world, the only way for "coins" to circulate is through transactions, and the entire life cycle of coins is spent in transactions. The RegisterTransaction method for registering a salary asset is a transaction, the IssueTransaction for asset distribution is also a special transaction, the MinerTransaction for paying the fee to the miners is also a transaction, and even the ClaimTransaction method for reward distribution for each block is also a transaction. So let's take a look at the father of all transaction types - the transaction base class Transaction. Transaction key fields are as follows:

Source code location: neo/Core/Transaction.cs

        /// <summary>
        /// 交易类型
        /// </summary>
        public readonly TransactionType Type;
        /// <summary>
        /// 版本
        /// </summary>
        public byte Version;
        /// <summary>
        /// 该交易所具备的额外特性
        /// </summary>
        public TransactionAttribute[] Attributes;
        /// <summary>
        /// 输入列表
        /// </summary>
        public CoinReference[] Inputs;
        /// <summary>
        /// 输出列表
        /// </summary>
        public TransactionOutput[] Outputs;
        /// <summary>
        /// 用于验证该交易的脚本列表
        /// </summary>
        public Witness[] Scripts { get; set; }

It can be seen that, for each transaction, it is necessary to clearly specify the source Inputs of the transaction assets and the Outputs where the transaction assets go. When each wallet is networked to synchronize the blockchain, it will check every transaction on the blockchain. If the transaction has Outputs pointing to its own account, a new CoinReference object will be created to record the transfer, and then try to log in Look it up in the asset list recorded locally. If the transfer has been recorded, change the asset status to Confirmed. If the current transfer has not been recorded, the reference object is used as the KEY, and the newly created Coin object is stored as the Value in its own asset list: Source code location: neo/Wallets/WalletIndexer.cs/ProcessBlock

                for (ushort index = 0; index < tx.Outputs.Length; index++)
                {
                    TransactionOutput output = tx.Outputs[index];
                    if (accounts_tracked.ContainsKey(output.ScriptHash))
                    {
                        CoinReference reference = new CoinReference
                        {
                            PrevHash = tx.Hash,
                            PrevIndex = index
                        };
                        if (coins_tracked.TryGetValue(reference, out Coin coin))
                        {
                            coin.State |= CoinState.Confirmed;
                        }
                        else
                        {
                            accounts_tracked[output.ScriptHash].Add(reference);
                            coins_tracked.Add(reference, coin = new Coin
                            {
                                Reference = reference,
                                Output = output,
                                State = CoinState.Confirmed
                            });
                        }
                        batch.Put(SliceBuilder.Begin(DataEntryPrefix.ST_Coin).Add(reference), SliceBuilder.Begin().Add(output).Add((byte)coin.State));
                        accounts_changed.Add(output.ScriptHash);
                    }

The asset source of each transaction comes from the data recorded in this asset list. Since every asset will record prehash, which means that every asset can be traced in the blockchain, and at the same time, we can also know the answer to another question, that is, in the NEO network,” "Coin" is just a digital concept and has no entity. The schematic diagram of assets circulating among users is as follows:

Assets circulate among users

It can be seen that after the assets are mined, the entire circulation process is a tree-like structure along with the transaction process. But for each asset, it's structured like this:

Asset circulation structure

As can be seen from the diagram, for each asset, its origin can be traced all the way to the block it was originally mined.

0x04 Release new assets

The NEO network supports users to publish their own assets. As mentioned above, both NEO and GAS are assets released through special transactions in the genesis block. So how do users publish their assets? This part of the code I found from the source code of the neo-gui-nel project: Source code location: neo-gui-nel/neo-gui/UI/AssetRegisterDialog.cs

            using (ScriptBuilder sb = new ScriptBuilder())
            {
                sb.EmitSysCall("Neo.Asset.Create", asset_type, name, amount, precision, owner, admin, issuer);
                return new InvocationTransaction
                {
                    Attributes = new[]
                    {
                        new TransactionAttribute
                        {
                            Usage = TransactionAttributeUsage.Script,
                            Data = Contract.CreateSignatureRedeemScript(owner).ToScriptHash().ToArray()
                        }
                    },
                    Script = sb.ToArray()
                };
            }

You can see that the system call "Neo.Asset.Create" is made here, which triggers the Asset_Create method in StateMachine.cs:

Source code location: neo/SmartContract/StateMachie.cs/StateMachine

Register("Neo.Asset.Create", Asset_Create);

In the Asset_Create method, the contract is constructed according to the property information of the new asset passed in. The explanation of the smart contract part will be carried out in the next blog, and will not be explained in detail here.

Finally: I am developing the NEO light wallet WeChat applet, mainly using the wepy framework. Interested friends are welcome to participate. NEOThinWallet for Wechat Miniprogram

{{o.name}}
{{m.name}}

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324216577&siteId=291194637
Recommended