From 1a7af6900ce93289126868ef651fff937fb5cfd1 Mon Sep 17 00:00:00 2001 From: vasmohi Date: Thu, 20 Jun 2024 18:37:58 +0530 Subject: [PATCH 01/16] Added ACS0-Contract Deployment Standard --- .../ACS0 - Contract Deployment Standard.md | 424 ++++++++++++++++++ 1 file changed, 424 insertions(+) create mode 100644 docs/Reference/ACS Introduction/ACS0 - Contract Deployment Standard.md diff --git a/docs/Reference/ACS Introduction/ACS0 - Contract Deployment Standard.md b/docs/Reference/ACS Introduction/ACS0 - Contract Deployment Standard.md new file mode 100644 index 0000000..e832f1a --- /dev/null +++ b/docs/Reference/ACS Introduction/ACS0 - Contract Deployment Standard.md @@ -0,0 +1,424 @@ +ACS0 - Contract Deployment Standard +=================================== + +ACS0 is used to manage the deployment and update of contracts. + +Interface +--------- + +The contract inherited from ACS0 needs to implement the following interfaces: + +Methods +~~~~~~~ + +| Method Name | Request Type | Response Type | Description | +|--------------------------------------|---------------------------------------------------------------------------|----------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------| +| DeploySystemSmartContract | `acs0.SystemContractDeploymentInput <#acs0.SystemContractDeploymentInput>` | `aelf.Address <#aelf.Address>` | Deploy a system smart contract on chain and return the address of the system contract deployed. | +| DeploySmartContract | `acs0.ContractDeploymentInput <#acs0.ContractDeploymentInput>` | `aelf.Address <#aelf.Address>` | Deploy a smart contract on chain and return the address of the contract deployed. | +| UpdateSmartContract | `acs0.ContractUpdateInput <#acs0.ContractUpdateInput>` | `aelf.Address <#aelf.Address>` | Update a smart contract on chain. | +| ProposeNewContract | `acs0.ContractDeploymentInput <#acs0.ContractDeploymentInput>` | `aelf.Hash <#aelf.Hash>` | Create a proposal to deploy a new contract and returns the id of the proposed contract. | +| ProposeContractCodeCheck | `acs0.ContractCodeCheckInput <#acs0.ContractCodeCheckInput>` | `aelf.Hash <#aelf.Hash>` | Create a proposal to check the code of a contract and return the id of the proposed contract. | +| ProposeUpdateContract | `acs0.ContractUpdateInput <#acs0.ContractUpdateInput>` | `aelf.Hash <#aelf.Hash>` | Create a proposal to update the specified contract and return the id of the proposed contract. | +| ReleaseApprovedContract | `acs0.ReleaseContractInput <#acs0.ReleaseContractInput>` | `google.protobuf.Empty <#google.protobuf.Empty>` | Release the contract proposal which has been approved. | +| ReleaseCodeCheckedContract | `acs0.ReleaseContractInput <#acs0.ReleaseContractInput>` | `google.protobuf.Empty <#google.protobuf.Empty>` | Release the proposal which has passed the code check. | +| ValidateSystemContractAddress | `acs0.ValidateSystemContractAddressInput <#acs0.ValidateSystemContractAddressInput>` | `google.protobuf.Empty <#google.protobuf.Empty>` | Validate whether the input system contract exists. | +| SetContractProposerRequiredState | `google.protobuf.BoolValue <#google.protobuf.BoolValue>` | `google.protobuf.Empty <#google.protobuf.Empty>` | Set authority of contract deployment. | +| CurrentContractSerialNumber | `google.protobuf.Empty <#google.protobuf.Empty>` | `google.protobuf.Int64Value <#google.protobuf.Int64Value>` | Get the current serial number of genesis contract (corresponds to the serial number that will be given to the next deployed contract). | +| GetContractInfo | `aelf.Address <#aelf.Address>` | `acs0.ContractInfo <#acs0.ContractInfo>` | Get detailed information about the specified contract. | +| GetContractAuthor | `aelf.Address <#aelf.Address>` | `aelf.Address <#aelf.Address>` | Get author of the specified contract. | +| GetContractHash | `aelf.Address <#aelf.Address>` | `aelf.Hash <#aelf.Hash>` | Get the code hash of the contract about the specified address. | +| GetContractAddressByName | `aelf.Hash <#aelf.Hash>` | `aelf.Address <#aelf.Address>` | Get the address of a system contract by its name. | +| GetSmartContractRegistrationByAddress| `aelf.Address <#aelf.Address>` | `aelf.SmartContractRegistration <#aelf.SmartContractRegistration>` | Get the registration of a smart contract by its address. | +| GetSmartContractRegistrationByCodeHash | `aelf.Hash <#aelf.Hash>` | `aelf.SmartContractRegistration <#aelf.SmartContractRegistration>` | Get the registration of a smart contract by code hash. | +| DeployUserSmartContract | `acs0.ContractDeploymentInput <#acs0.ContractDeploymentInput>` | `acs0.DeployUserSmartContractOutput <#acs0.DeployUserSmartContractOutput>` | Deploy a user smart contract on chain and return the hash of the contract code. | +| UpdateUserSmartContract | `acs0.ContractUpdateInput <#acs0.ContractUpdateInput>` | `google.protobuf.Empty <#google.protobuf.Empty>` | Update a user smart contract on chain. | +| ReleaseApprovedUserSmartContract | `acs0.ReleaseContractInput <#acs0.ReleaseContractInput>` | `google.protobuf.Empty <#google.protobuf.Empty>` | Release the proposal which has passed the code check. | +| PerformDeployUserSmartContract | `acs0.ContractDeploymentInput <#acs0.ContractDeploymentInput>` | `aelf.Address <#aelf.Address>` | Perform user contract deployment. | +| PerformUpdateUserSmartContract | `acs0.ContractUpdateInput <#acs0.ContractUpdateInput>` | `google.protobuf.Empty <#google.protobuf.Empty>` | Perform user contract update. | +| SetContractAuthor | `acs0.SetContractAuthorInput <#acs0.SetContractAuthorInput>` | `google.protobuf.Empty <#google.protobuf.Empty>` | Set author of the specified contract. | + +Types +~~~~~ + +
+ +acs0.AuthorUpdated +''''''''''''''''''' + +| Field | Type | Description | Label | +|-------------|-----------------------------------|----------------------------------------------|---------| +| address | `aelf.address <#aelf.address>` | The byte array of the contract code. | | +| old_author | `aelf.address <#aelf.address>` | The category of contract code(0: C#). | | +| CrossChainCreateToken | `aelf.address <#aelf.address>` | Indicates if the contract is the system contract. | | + +
+ +acs0.CodeCheckRequired +^^^^^^^^^^^^^^^^^^^^^^ + +| Field | Type | Description | Label | +|---------------------------------|------------------------------|----------------------------------------------------------|---------| +| code | `bytes <#bytes>` | The byte array of the contract code. | | +| proposed_contract_input_hash | `aelf.Hash <#aelf.Hash>` | The id of the proposed contract. | | +| category | `sint32 <#sint32>` | The category of contract code(0: C#). | | +| is_system_contract | `bool <#bool>` | Indicates if the contract is the system contract. | | +| is_user_contract | `bool <#bool>` | Indicates if the contract is the user contract. | | + +
+ +acs0.CodeUpdated +^^^^^^^^^^^^^^^^ + +| Field | Type | Description | Label | +|------------------|------------------------------------|-----------------------------------------|---------| +| address | `aelf.Address <#aelf.Address>` | The address of the updated contract. | | +| old_code_hash | `aelf.Hash <#aelf.Hash>` | The byte array of the old contract code.| | +| new_code_hash | `aelf.Hash <#aelf.Hash>` | The byte array of the new contract code.| | +| version | `int32 <#int32>` | The version of the current contract. | | + +
+ +acs0.ContractCodeCheckInput +^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +| Field | Type | Description | Label | +|-------------------------------|------------------------------|-----------------------------------------------------------------------------|---------| +| contract_input | `bytes <#bytes>` | The byte array of the contract code to be checked. | | +| is_contract_deployment | `bool <#bool>` | Whether the input contract is to be deployed or updated. | | +| code_check_release_method | `string <#string>` | Method to call after code check complete(DeploySmartContract or UpdateSmartContract). | | +| proposed_contract_input_hash | `aelf.Hash <#aelf.Hash>` | The id of the proposed contract. | | +| category | `sint32 <#sint32>` | The category of contract code(0: C#). | | +| is_system_contract | `bool <#bool>` | Indicates if the contract is the system contract. | | + +
+ +acs0.ContractDeployed +^^^^^^^^^^^^^^^^^^^^^ + +| Field | Type | Description | Label | +|----------------------|------------------------------------|------------------------------------------------------|---------| +| author | `aelf.Address <#aelf.Address>` | The author of the contract, this is the person who deployed the contract. | | +| code_hash | `aelf.Hash <#aelf.Hash>` | The hash of the contract code. | | +| address | `aelf.Address <#aelf.Address>` | The address of the contract. | | +| version | `int32 <#int32>` | The version of the current contract. | | +| Name | `aelf.Hash <#aelf.Hash>` | The name of the contract. It has to be unique. | | +| contract_version | `string <#string>` | The version of the current contract. | + +
+ + +acs0.ContractDeploymentInput +^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +| Field | Type | Description | Label | +|----------|-----------------------|-----------------------------------------|---------| +| category | `sint32 <#sint32>` | The category of contract code(0: C#). | | +| code | `bytes <#bytes>` | The byte array of the contract code. | | + +
+ +acs0.DeployUserSmartContractOutput +''''''''''''''''''''''''''''''''''' + +| Field | Type | Description | Label | +|------------|------------------------|---------------------------------------------|---------| +| code_hash | `aelf.Hash <#aelf.Hash>` | The deployed or updated contract code hash. | | + +
+ +acs0.ContractInfo +^^^^^^^^^^^^^^^^^ + +| Field | Type | Description | Label | +|--------------------|-------------------------|-----------------------------------------------------------------------------|---------| +| serial_number | `int64 <#int64>` | The serial number of the contract. | | +| author | `aelf.Address <#aelf.Address>` | The author of the contract, this is the person who deployed the contract. | | +| category | `sint32 <#sint32>` | The category of contract code(0: C#). | | +| code_hash | `aelf.Hash <#aelf.Hash>` | The hash of the contract code. | | +| is_system_contract | `bool <#bool>` | Whether it is a system contract. | | +| version | `int32 <#int32>` | The version of the current contract. | | +| contract_version | `string <#string>` | The version of the current contract. | | +| is_user_contract | `bool <#bool>` | Indicates if the contract is the user contract. | | + +
+ +acs0.ContractProposed +^^^^^^^^^^^^^^^^^^^^^ + +| Field | Type | Description | Label | +|---------------------------------|-------------------------|------------------------------------|---------| +| proposed_contract_input_hash | `aelf.Hash <#aelf.Hash>` | The id of the proposed contract. | | + +
+ +acs0.ContractUpdateInput +^^^^^^^^^^^^^^^^^^^^^^^^ + +| Field | Type | Description | Label | +|----------|-------------------------|--------------------------------------------------|---------| +| address | `aelf.Address <#aelf.Address>` | The contract address that needs to be updated. | | +| code | `bytes <#bytes>` | The byte array of the new contract code. | | + +
+ +acs0.SetContractAuthorInput +''''''''''''''''''''''''''''' + +| Field | Type | Description | Label | +|-------------------|-------------------------|------------------------------------------------------|---------| +| contract_address | `aelf.Address <#aelf.Address>` | The author's contract address needs to be updated. | | +| new_author | `aelf.Address <#aelf.Address>` | The new contract author. | | + +
+ +acs0.ReleaseContractInput +^^^^^^^^^^^^^^^^^^^^^^^^^ + +| Field | Type | Description | Label | +|---------------------------------|-------------------------|------------------------------------|---------| +| proposal_id | `aelf.Hash <#aelf.Hash>` | The hash of the proposal. | | +| proposed_contract_input_hash | `aelf.Hash <#aelf.Hash>` | The id of the proposed contract. | | + +
+ +acs0.SystemContractDeploymentInput +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +| Field | Type | Description | Label | +|--------------------------------|---------------------------------------------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------|---------| +| category | `sint32 <#sint32>` | The category of contract code(0: C#). | | +| code | `bytes <#bytes>` | The byte array of the contract code. | | +| name | `aelf.Hash <#aelf.Hash>` | The name of the contract. It has to be unique. | | +| transaction_method_call_list | `SystemContractDeploymentInput.SystemTransactionMethodCallList <#acs0.SystemContractDeploymentInput.SystemTransactionMethodCallList>` | An initial list of transactions for the system contract, which is executed in sequence when the contract is deployed. | + +
+ +acs0.SystemContractDeploymentInput.SystemTransactionMethodCall +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +| Field | Type | Description | Label | +|---------------|------------------------|-------------------------------------------|---------| +| method_name | `string <#string>` | The method name of system transaction. | | +| params | `bytes <#bytes>` | The params of system transaction method. | | + +
+ +acs0.SystemContractDeploymentInput.SystemTransactionMethodCallList +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +| Field | Type | Description | Label | +|-------|---------------------------------------------------------------------------------------------------------------------------|---------------------------------------|------------| +| value | `SystemContractDeploymentInput.SystemTransactionMethodCall <#acs0.SystemContractDeploymentInput.SystemTransactionMethodCall>` | The list of system transactions. | repeated | + +
+ +acs0.ValidateSystemContractAddressInput +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +| Field | Type | Description | Label | +|------------------------------|--------------------------------|------------------------------------|---------| +| system_contract_hash_name | `aelf.Hash <#aelf.Hash>` | The name hash of the contract. | | +| address | `aelf.Address <#aelf.Address>` | The address of the contract. | | + +
+ +aelf.Address +^^^^^^^^^^^^ + +| Field | Type | Description | Label | +|-------|----------------------|---------------|---------| +| value | `bytes <#bytes>` | | | + +
+ +aelf.BinaryMerkleTree +^^^^^^^^^^^^^^^^^^^^^ + +| Field | Type | Description | Label | +|-------------|---------------------|------------------------|------------| +| nodes | `Hash <#aelf.Hash>` | The leaf nodes. | repeated | +| root | `Hash <#aelf.Hash>` | The root node hash. | | +| leaf_count | `int32 <#int32>` | The count of leaf node.| | + +
+ +aelf.Hash +^^^^^^^^^ + +| Field | Type | Description | Label | +|-------|--------------------|---------------|---------| +| value | `bytes <#bytes>` | | | + +
+ +aelf.LogEvent +^^^^^^^^^^^^^ + +| Field | Type | Description | Label | +|-------------|---------------------------|--------------------------------------|------------| +| address | `Address <#aelf.Address>` | The contract address. | | +| name | `string <#string>` | The name of the log event. | | +| indexed | `bytes <#bytes>` | The indexed data, used to calculate bloom. | repeated | +| non_indexed | `bytes <#bytes>` | The non indexed data. | | + +
+ +aelf.MerklePath +^^^^^^^^^^^^^^^ + +| Field | Type | Description | Label | +|-------------------|-------------------------------------|------------------------------|------------| +| merkle_path_nodes | `MerklePathNode <#aelf.MerklePathNode>` | The merkle path nodes. | repeated | + +
+ +aelf.MerklePathNode +^^^^^^^^^^^^^^^^^^^ + +| Field | Type | Description | Label | +|-----------------------|--------------------|---------------------|---------| +| hash | `Hash <#aelf.Hash>`| The node hash. | | +| is_left_child_node | `bool <#bool>` | Whether it is a left child node. | | + +
+ +aelf.SInt32Value +^^^^^^^^^^^^^^^^ + +| Field | Type | Description | Label | +|-------|---------------------|---------------|---------| +| value | `sint32 <#sint32>` | | | + +
+ +aelf.SInt64Value +^^^^^^^^^^^^^^^^ + +| Field | Type | Description | Label | +|-------|---------------------|---------------|---------| +| value | `sint64 <#sint64>` | | | + +
+ +aelf.ScopedStatePath +^^^^^^^^^^^^^^^^^^^^ + +| Field | Type | Description | Label | +|---------|---------------------------------|----------------------------------------------|---------| +| address | `Address <#aelf.Address>` | The scope address, which will be the contract address. | | +| path | `StatePath <#aelf.StatePath>` | The path of contract state. | | + +
+ +aelf.SmartContractRegistration +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +| Field | Type | Description | Label | +|---------------------|-----------------------|-------------------------------------------|---------| +| category | `sint32 <#sint32>` | The category of contract code(0: C#). | | +| code | `bytes <#bytes>` | The byte array of the contract code. | | +| code_hash | `Hash <#aelf.Hash>` | The hash of the contract code. | | +| is_system_contract | `bool <#bool>` | Whether it is a system contract. | | +| version | `int32 <#int32>` | The version of the current contract. | | + +
+ +aelf.StatePath +^^^^^^^^^^^^^^ + +| Field | Type | Description | Label | +|---------|----------------------|---------------------------------------|------------| +| parts | `string <#string>` | The partial path of the state path. | repeated | + +
+ +aelf.Transaction +^^^^^^^^^^^^^^^^ + +| Field | Type | Description | Label | +|---------------------|-------------------------------|-----------------------------------------------------------------------------------------------------------|---------| +| from | `Address <#aelf.Address>` | The address of the sender of the transaction. | | +| to | `Address <#aelf.Address>` | The address of the contract when calling a contract. | | +| ref_block_number | `int64 <#int64>` | The height of the referenced block hash. | | +| ref_block_prefix | `bytes <#bytes>` | The first four bytes of the referenced block hash. | | +| method_name | `string <#string>` | The name of a method in the smart contract at the To address. | | +| params | `bytes <#bytes>` | The parameters to pass to the smart contract method. | | +| signature | `bytes <#bytes>` | When signing a transaction it's actually a subset of the fields: from/to and the target method as well as the parameter that were given. It also contains the reference block number and prefix. | | + +
+ +aelf.TransactionExecutingStateSet +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +| Field | Type | Description | Label | +|---------|------------------------------------------------------------------|-------------------------|------------| +| writes | `TransactionExecutingStateSet.WritesEntry <#aelf.TransactionExecutingStateSet.WritesEntry>` | The changed states. | repeated | +| reads | `TransactionExecutingStateSet.ReadsEntry <#aelf.TransactionExecutingStateSet.ReadsEntry>` | The read states. | repeated | +| deletes | `TransactionExecutingStateSet.DeletesEntry <#aelf.TransactionExecutingStateSet.DeletesEntry>` | The deleted states. | repeated | + +
+ +aelf.TransactionExecutingStateSet.DeletesEntry +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +| Field | Type | Description | Label | +|---------|----------------------|---------------|---------| +| key | `string <#string>` | | | +| value | `bool <#bool>` | | | + +
+ +aelf.TransactionExecutingStateSet.ReadsEntry +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +| Field | Type | Description | Label | +|---------|----------------------|---------------|---------| +| key | `string <#string>` | | | +| value | `bool <#bool>` | | | + +
+ +aelf.TransactionExecutingStateSet.WritesEntry +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +| Field | Type | Description | Label | +|---------|----------------------|---------------|---------| +| key | `string <#string>` | | | +| value | `bytes <#bytes>` | | | + +
+ +aelf.TransactionResult +^^^^^^^^^^^^^^^^^^^^^^ + +| Field | Type | Description | Label | +|-------------------|-------------------------------|---------------------------------------------------------------------------------------------------|------------| +| transaction_id | `Hash <#aelf.Hash>` | The transaction id. | | +| status | `TransactionResultStatus <#aelf.TransactionResultStatus>` | The transaction result status. | | +| logs | `LogEvent <#aelf.LogEvent>` | The log events. | repeated | +| bloom | `bytes <#bytes>` | Bloom filter for transaction logs. A transaction log event can be defined in the contract and stored in the bloom filter after the transaction is executed. | | +| return_value | `bytes <#bytes>` | The return value of the transaction execution. | | +| block_number | `int64 <#int64>` | The height of the block hat packages the transaction. | | +| block_hash | `Hash <#aelf.Hash>` | The hash of the block hat packages the transaction. | | +| error | `string <#string>` | Failed execution error message. | | + +
+ +aelf.TransactionResultStatus +^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +| Name | Number | Description | +|--------------------------|----------|-----------------------------------------------------------------------------------------------| +| NOT_EXISTED | 0 | The execution result of the transaction does not exist. | +| PENDING | 1 | The transaction is in the transaction pool waiting to be packaged. | +| FAILED | 2 | Transaction execution failed. | +| MINED | 3 | The transaction was successfully executed and successfully packaged into a block. | +| CONFLICT | 4 | When executed in parallel, there are conflicts with other transactions. | +| PENDING_VALIDATION | 5 | The transaction is waiting for validation. | +| NODE_VALIDATION_FAILED | 6 | Transaction validation failed. | + +Example +------- + +ACS0 declares methods for the scenes about contract deployment and update. AElf provides the implementation for ACS0, ``Genesis Contract``. +You can refer to the implementation of the :doc:`Genesis contract api<../smart-contract-api/genesis>`. From 10fe8fef124407cb0c4cb376aa3941b211a3c541 Mon Sep 17 00:00:00 2001 From: vasmohi Date: Thu, 20 Jun 2024 19:08:31 +0530 Subject: [PATCH 02/16] Added ACS1-Transaction Fee Standard --- .../ACS1 - Transaction Fee Standard | 61 +++++++++++++++++++ 1 file changed, 61 insertions(+) create mode 100644 docs/Reference/ACS Introduction/ACS1 - Transaction Fee Standard diff --git a/docs/Reference/ACS Introduction/ACS1 - Transaction Fee Standard b/docs/Reference/ACS Introduction/ACS1 - Transaction Fee Standard new file mode 100644 index 0000000..5127662 --- /dev/null +++ b/docs/Reference/ACS Introduction/ACS1 - Transaction Fee Standard @@ -0,0 +1,61 @@ +```markdown +ACS1 - Transaction Fee Standard + +ACS1 manages transaction fees and is integrated into contracts needing fee management. + +### Interface + +Contracts inheriting ACS1 must implement the following APIs: + +#### Methods + +| Method Name | Request Type | Response Type | Description | +|--------------------------|--------------------------|-----------------------------|-------------------------------------------------------------| +| SetMethodFee | acs1.MethodFees | google.protobuf.Empty | Sets fees for a specified method, overriding existing fees. | +| ChangeMethodFeeController| AuthorityInfo | google.protobuf.Empty | Changes the method fee controller (default: parliament). | +| GetMethodFee | google.protobuf.StringValue | acs1.MethodFees | Retrieves method fee information by method name. | +| GetMethodFeeController | google.protobuf.Empty | AuthorityInfo | Retrieves the current method fee controller. | + +### Types + +#### acs1.MethodFee + +| Field | Type | Description | Label | +|---------------|---------------|---------------------------------|-----------| +| symbol | string | Token symbol of the method fee. | | +| basic_fee | int64 | Fee amount to be charged. | | + +#### acs1.MethodFees + +| Field | Type | Description | Label | +|---------------|---------------|---------------------------------|-----------| +| method_name | string | Name of the method. | | +| fees | MethodFee | List of fees for the method. | repeated | +| is_size_fee_free | bool | Indicates if size fee is free. | | + +#### AuthorityInfo + +| Field | Type | Description | Label | +|-------------------|--------------------|-------------------------------------------|-----------| +| contract_address | aelf.Address | Contract address of the controller. | | +| owner_address | aelf.Address | Address of the owner of the contract. | | + +**Note:** Only system contracts on the main chain can implement ACS1. + +### Usage + +In aelf, transaction fees are managed by ACS1 through a pre-transaction generated by FeeChargePreExecutionPlugin. This plugin charges transaction fees before processing the main transaction. + +### Implementation + +Implement ACS1 by defining GetMethodFee to manage method-specific fees. Optionally, use MappedState for efficient fee management across methods. + +### Test + +Test ACS1 functionality by calling GetMethodFee and GetMethodFeeController to validate expected behavior. + +### Example + +All aelf system contracts implement ACS1, providing a reference for implementation. +``` +This markdown condenses the provided information into a simplified and structured format suitable for developer documentation. \ No newline at end of file From 253e358baac7c133c136b9b52a269100d044db72 Mon Sep 17 00:00:00 2001 From: vasmohi Date: Thu, 20 Jun 2024 22:18:35 +0530 Subject: [PATCH 03/16] Added ACS2 and updated ACS1 --- .../ACS1 - Transaction Fee Standard | 111 ++++++++++++++++- .../ACS10 - Dividend Pool Standard | 0 .../ACS11 - Cross Chain Consensus Standard | 0 .../ACS12 - User Contract Standard | 0 .../ACS2 - Parallel Execution Standard | 114 ++++++++++++++++++ .../ACS3 - Contract Proposal Standard | 0 .../ACS4 - Consensus Standard | 0 .../ACS5 - Contract Threshold Standard | 0 .../ACS6 - Random Number Generation | 0 .../ACS7 - Cross Chain Standard | 0 ... - Transaction Resource Token Fee Standard | 0 .../ACS9 - Contract Profit Dividend Standard | 0 12 files changed, 221 insertions(+), 4 deletions(-) create mode 100644 docs/Reference/ACS Introduction/ACS10 - Dividend Pool Standard create mode 100644 docs/Reference/ACS Introduction/ACS11 - Cross Chain Consensus Standard create mode 100644 docs/Reference/ACS Introduction/ACS12 - User Contract Standard create mode 100644 docs/Reference/ACS Introduction/ACS2 - Parallel Execution Standard create mode 100644 docs/Reference/ACS Introduction/ACS3 - Contract Proposal Standard create mode 100644 docs/Reference/ACS Introduction/ACS4 - Consensus Standard create mode 100644 docs/Reference/ACS Introduction/ACS5 - Contract Threshold Standard create mode 100644 docs/Reference/ACS Introduction/ACS6 - Random Number Generation create mode 100644 docs/Reference/ACS Introduction/ACS7 - Cross Chain Standard create mode 100644 docs/Reference/ACS Introduction/ACS8 - Transaction Resource Token Fee Standard create mode 100644 docs/Reference/ACS Introduction/ACS9 - Contract Profit Dividend Standard diff --git a/docs/Reference/ACS Introduction/ACS1 - Transaction Fee Standard b/docs/Reference/ACS Introduction/ACS1 - Transaction Fee Standard index 5127662..a713fd6 100644 --- a/docs/Reference/ACS Introduction/ACS1 - Transaction Fee Standard +++ b/docs/Reference/ACS Introduction/ACS1 - Transaction Fee Standard @@ -1,4 +1,3 @@ -```markdown ACS1 - Transaction Fee Standard ACS1 manages transaction fees and is integrated into contracts needing fee management. @@ -46,6 +45,112 @@ Contracts inheriting ACS1 must implement the following APIs: In aelf, transaction fees are managed by ACS1 through a pre-transaction generated by FeeChargePreExecutionPlugin. This plugin charges transaction fees before processing the main transaction. +The usage of ChargeTransactionFees method is implemented as below: + + ```cs + /// + /// Related transactions will be generated by acs1 pre-plugin service, + /// and will be executed before the origin transaction. + /// + /// + /// + public override BoolValue ChargeTransactionFees(ChargeTransactionFeesInput input) + { + // ... + // Record tx fee bill during current charging process. + var bill = new TransactionFeeBill(); + var fromAddress = Context.Sender; + var methodFees = Context.Call(input.ContractAddress, nameof(GetMethodFee), + new StringValue {Value = input.MethodName}); + var successToChargeBaseFee = true; + if (methodFees != null && methodFees.Fees.Any()) + { + successToChargeBaseFee = ChargeBaseFee(GetBaseFeeDictionary(methodFees), ref bill); + } + var successToChargeSizeFee = true; + if (!IsMethodFeeSetToZero(methodFees)) + { + // Then also do not charge size fee. + successToChargeSizeFee = ChargeSizeFee(input, ref bill); + } + // Update balances. + foreach (var tokenToAmount in bill.FeesMap) + { + ModifyBalance(fromAddress, tokenToAmount.Key, -tokenToAmount.Value); + Context.Fire(new TransactionFeeCharged + { + Symbol = tokenToAmount.Key, + Amount = tokenToAmount.Value + }); + if (tokenToAmount.Value == 0) + { + //Context.LogDebug(() => $"Maybe incorrect charged tx fee of {tokenToAmount.Key}: it's 0."); + } + } + return new BoolValue {Value = successToChargeBaseFee && successToChargeSizeFee}; + } + ``` + +The usage of TransferTransactionFeesToFeeReceiver method is implemented as below: + + ```cs + /// + /// Burn 10% of tx fees. + /// If Side Chain didn't set FeeReceiver, burn all. + /// + /// + /// + private void TransferTransactionFeesToFeeReceiver(string symbol, long totalAmount) + { + Context.LogDebug(() => "Transfer transaction fee to receiver."); + if (totalAmount <= 0) return; + var burnAmount = totalAmount.Div(10); + if (burnAmount > 0) + Context.SendInline(Context.Self, nameof(Burn), new BurnInput + { + Symbol = symbol, + Amount = burnAmount + }); + var transferAmount = totalAmount.Sub(burnAmount); + if (transferAmount == 0) + return; + var treasuryContractAddress = + Context.GetContractAddressByName(SmartContractConstants.TreasuryContractSystemName); + if ( treasuryContractAddress!= null) + { + // Main chain would donate tx fees to dividend pool. + if (State.DividendPoolContract.Value == null) + State.DividendPoolContract.Value = treasuryContractAddress; + State.DividendPoolContract.Donate.Send(new DonateInput + { + Symbol = symbol, + Amount = transferAmount + }); + } + else + { + if (State.FeeReceiver.Value != null) + { + Context.SendInline(Context.Self, nameof(Transfer), new TransferInput + { + To = State.FeeReceiver.Value, + Symbol = symbol, + Amount = transferAmount, + }); + } + else + { + // Burn all! + Context.SendInline(Context.Self, nameof(Burn), new BurnInput + { + Symbol = symbol, + Amount = transferAmount + }); + } + } + } + ``` + ### Implementation Implement ACS1 by defining GetMethodFee to manage method-specific fees. Optionally, use MappedState for efficient fee management across methods. @@ -56,6 +161,4 @@ Test ACS1 functionality by calling GetMethodFee and GetMethodFeeController to va ### Example -All aelf system contracts implement ACS1, providing a reference for implementation. -``` -This markdown condenses the provided information into a simplified and structured format suitable for developer documentation. \ No newline at end of file +All aelf system contracts implement ACS1, providing a reference for implementation. \ No newline at end of file diff --git a/docs/Reference/ACS Introduction/ACS10 - Dividend Pool Standard b/docs/Reference/ACS Introduction/ACS10 - Dividend Pool Standard new file mode 100644 index 0000000..e69de29 diff --git a/docs/Reference/ACS Introduction/ACS11 - Cross Chain Consensus Standard b/docs/Reference/ACS Introduction/ACS11 - Cross Chain Consensus Standard new file mode 100644 index 0000000..e69de29 diff --git a/docs/Reference/ACS Introduction/ACS12 - User Contract Standard b/docs/Reference/ACS Introduction/ACS12 - User Contract Standard new file mode 100644 index 0000000..e69de29 diff --git a/docs/Reference/ACS Introduction/ACS2 - Parallel Execution Standard b/docs/Reference/ACS Introduction/ACS2 - Parallel Execution Standard new file mode 100644 index 0000000..9e41c89 --- /dev/null +++ b/docs/Reference/ACS Introduction/ACS2 - Parallel Execution Standard @@ -0,0 +1,114 @@ +ACS2 - Parallel Execution Standard + +ACS2 enables parallel execution of transactions by providing necessary resource information. + +### Interface + +A contract inheriting ACS2 must implement: + +#### Methods + +| Method Name | Request Type | Response Type | Description | +|------------------|---------------------|---------------------|-------------------------------------------------------| +| GetResourceInfo | aelf.Transaction | acs2.ResourceInfo | Retrieves resource dependencies for transaction exec. | + +### Types + +#### acs2.ResourceInfo + +| Field | Type | Description | Label | +|-------------------|----------------------|------------------------------------|-----------| +| write_paths | aelf.ScopedStatePath | State paths written during execution| repeated | +| read_paths | aelf.ScopedStatePath | State paths read during execution | repeated | +| non_parallelizable| bool | Indicates if transaction is non-parallelizable.| | + +#### Other Types (Omitted for brevity) + +Several other types like `aelf.Address`, `aelf.BinaryMerkleTree`, `aelf.LogEvent`, etc., are used within `acs2.ResourceInfo`. + +### Usage + +aelf uses State Paths to manage data storage, ensuring transaction grouping based on accessed paths for efficient parallel execution. + +### Implementation + +Token contract, for example, modifies balances through method Transfer. GetResourceInfo must notify ITransactionGrouper of accessed state paths. + +```cs +var args = TransferInput.Parser.ParseFrom(txn.Params); +var resourceInfo = new ResourceInfo +{ + Paths = + { + GetPath(nameof(TokenContractState.Balances), txn.From.ToString(), args.Symbol), + GetPath(nameof(TokenContractState.Balances), args.To.ToString(), args.Symbol), + } +}; +return resourceInfo; +``` + +### Test +Test transaction parallelizability using ITransactionGrouper's GroupAsync method with sample transactions. + + ```cs + var keyPair1 = SampleECKeyPairs.KeyPairs[0]; + var acs2DemoContractStub1 = GetACS2DemoContractStub(keyPair1); + var keyPair2 = SampleECKeyPairs.KeyPairs[1]; + var acs2DemoContractStub2 = GetACS2DemoContractStub(keyPair2); + + var transactionGrouper = Application.ServiceProvider.GetRequiredService(); + var blockchainService = Application.ServiceProvider.GetRequiredService(); + var chain = await blockchainService.GetChainAsync(); + + // Test parallel execution scenario + { + var groupedTransactions = await transactionGrouper.GroupAsync(new ChainContext + { + BlockHash = chain.BestChainHash, + BlockHeight = chain.BestChainHeight + }, new List + { + acs2DemoContractStub1.TransferCredits.GetTransaction(new TransferCreditsInput + { + To = Address.FromPublicKey(SampleECKeyPairs.KeyPairs[2].PublicKey), + Symbol = "ELF", + Amount = 1 + }), + acs2DemoContractStub2.TransferCredits.GetTransaction(new TransferCreditsInput + { + To = Address.FromPublicKey(SampleECKeyPairs.KeyPairs[3].PublicKey), + Symbol = "ELF", + Amount = 1 + }), + }); + groupedTransactions.Parallelizables.Count.ShouldBe(2); + } + + // Test non-parallel execution scenario + { + var groupedTransactions = await transactionGrouper.GroupAsync(new ChainContext + { + BlockHash = chain.BestChainHash, + BlockHeight = chain.BestChainHeight + }, new List + { + acs2DemoContractStub1.TransferCredits.GetTransaction(new TransferCreditsInput + { + To = Address.FromPublicKey(SampleECKeyPairs.KeyPairs[2].PublicKey), + Symbol = "ELF", + Amount = 1 + }), + acs2DemoContractStub2.TransferCredits.GetTransaction(new TransferCreditsInput + { + To = Address.FromPublicKey(SampleECKeyPairs.KeyPairs[2].PublicKey), + Symbol = "ELF", + Amount = 1 + }), + }); + groupedTransactions.Parallelizables.Count.ShouldBe(1); + } + ``` + +### Example + +For an example of implementing GetResourceInfo, refer to the MultiToken contract, ensuring transaction fees are considered for the keys involved. diff --git a/docs/Reference/ACS Introduction/ACS3 - Contract Proposal Standard b/docs/Reference/ACS Introduction/ACS3 - Contract Proposal Standard new file mode 100644 index 0000000..e69de29 diff --git a/docs/Reference/ACS Introduction/ACS4 - Consensus Standard b/docs/Reference/ACS Introduction/ACS4 - Consensus Standard new file mode 100644 index 0000000..e69de29 diff --git a/docs/Reference/ACS Introduction/ACS5 - Contract Threshold Standard b/docs/Reference/ACS Introduction/ACS5 - Contract Threshold Standard new file mode 100644 index 0000000..e69de29 diff --git a/docs/Reference/ACS Introduction/ACS6 - Random Number Generation b/docs/Reference/ACS Introduction/ACS6 - Random Number Generation new file mode 100644 index 0000000..e69de29 diff --git a/docs/Reference/ACS Introduction/ACS7 - Cross Chain Standard b/docs/Reference/ACS Introduction/ACS7 - Cross Chain Standard new file mode 100644 index 0000000..e69de29 diff --git a/docs/Reference/ACS Introduction/ACS8 - Transaction Resource Token Fee Standard b/docs/Reference/ACS Introduction/ACS8 - Transaction Resource Token Fee Standard new file mode 100644 index 0000000..e69de29 diff --git a/docs/Reference/ACS Introduction/ACS9 - Contract Profit Dividend Standard b/docs/Reference/ACS Introduction/ACS9 - Contract Profit Dividend Standard new file mode 100644 index 0000000..e69de29 From 76162f9fc24277b68245795b633479516be24535 Mon Sep 17 00:00:00 2001 From: vasmohi Date: Sun, 23 Jun 2024 13:51:16 +0530 Subject: [PATCH 04/16] Updated ACS0 and ACS1 --- .../ACS0 - Contract Deployment Standard.md | 10 ++--- ...ard => ACS1 - Transaction Fee Standard.md} | 41 +++++++++++++++++++ 2 files changed, 46 insertions(+), 5 deletions(-) rename docs/Reference/ACS Introduction/{ACS1 - Transaction Fee Standard => ACS1 - Transaction Fee Standard.md} (86%) diff --git a/docs/Reference/ACS Introduction/ACS0 - Contract Deployment Standard.md b/docs/Reference/ACS Introduction/ACS0 - Contract Deployment Standard.md index e832f1a..7039e25 100644 --- a/docs/Reference/ACS Introduction/ACS0 - Contract Deployment Standard.md +++ b/docs/Reference/ACS Introduction/ACS0 - Contract Deployment Standard.md @@ -1,14 +1,14 @@ -ACS0 - Contract Deployment Standard +# ACS0 - Contract Deployment Standard =================================== ACS0 is used to manage the deployment and update of contracts. -Interface +## Interface --------- The contract inherited from ACS0 needs to implement the following interfaces: -Methods +## Methods ~~~~~~~ | Method Name | Request Type | Response Type | Description | @@ -37,8 +37,8 @@ Methods | PerformUpdateUserSmartContract | `acs0.ContractUpdateInput <#acs0.ContractUpdateInput>` | `google.protobuf.Empty <#google.protobuf.Empty>` | Perform user contract update. | | SetContractAuthor | `acs0.SetContractAuthorInput <#acs0.SetContractAuthorInput>` | `google.protobuf.Empty <#google.protobuf.Empty>` | Set author of the specified contract. | -Types -~~~~~ + +## Types
diff --git a/docs/Reference/ACS Introduction/ACS1 - Transaction Fee Standard b/docs/Reference/ACS Introduction/ACS1 - Transaction Fee Standard.md similarity index 86% rename from docs/Reference/ACS Introduction/ACS1 - Transaction Fee Standard rename to docs/Reference/ACS Introduction/ACS1 - Transaction Fee Standard.md index a713fd6..64e5992 100644 --- a/docs/Reference/ACS Introduction/ACS1 - Transaction Fee Standard +++ b/docs/Reference/ACS Introduction/ACS1 - Transaction Fee Standard.md @@ -155,6 +155,47 @@ The usage of TransferTransactionFeesToFeeReceiver method is implemented as below Implement ACS1 by defining GetMethodFee to manage method-specific fees. Optionally, use MappedState for efficient fee management across methods. +To set method fees, implement the `GetMethodFee` method. + +For methods `Foo1`, `Foo2`, `Bar1`, and `Bar2`, set fees to 1, 1, 2, and 2 ELF respectively. The fees can be hardcoded like this: + +```csharp +public override MethodFees GetMethodFee(StringValue input) +{ + if (input.Value == nameof(Foo1) || input.Value == nameof(Foo2)) + { + return new MethodFees + { + MethodName = input.Value, + Fees = + { + new MethodFee + { + BasicFee = 1_00000000, + Symbol = Context.Variables.NativeSymbol + } + } + }; + } + if (input.Value == nameof(Bar1) || input.Value == nameof(Bar2)) + { + return new MethodFees + { + MethodName = input.Value, + Fees = + { + new MethodFee + { + BasicFee = 2_00000000, + Symbol = Context.Variables.NativeSymbol + } + } + }; + } + return new MethodFees(); +} +``` + ### Test Test ACS1 functionality by calling GetMethodFee and GetMethodFeeController to validate expected behavior. From 02f44041cf6ddf4514d6aedaecb2b2bc45e686dd Mon Sep 17 00:00:00 2001 From: vasmohi Date: Mon, 24 Jun 2024 12:24:11 +0530 Subject: [PATCH 05/16] Updated ACS0 and ACS1 --- .../ACS0 - Contract Deployment Standard.md | 638 +++++++----------- .../ACS1 - Transaction Fee Standard.md | 337 +++++---- 2 files changed, 457 insertions(+), 518 deletions(-) diff --git a/docs/Reference/ACS Introduction/ACS0 - Contract Deployment Standard.md b/docs/Reference/ACS Introduction/ACS0 - Contract Deployment Standard.md index 7039e25..cba403d 100644 --- a/docs/Reference/ACS Introduction/ACS0 - Contract Deployment Standard.md +++ b/docs/Reference/ACS Introduction/ACS0 - Contract Deployment Standard.md @@ -1,424 +1,298 @@ # ACS0 - Contract Deployment Standard -=================================== -ACS0 is used to manage the deployment and update of contracts. +ACS0 manages contract deployment and updates. ## Interface ---------- - -The contract inherited from ACS0 needs to implement the following interfaces: - -## Methods -~~~~~~~ - -| Method Name | Request Type | Response Type | Description | -|--------------------------------------|---------------------------------------------------------------------------|----------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------| -| DeploySystemSmartContract | `acs0.SystemContractDeploymentInput <#acs0.SystemContractDeploymentInput>` | `aelf.Address <#aelf.Address>` | Deploy a system smart contract on chain and return the address of the system contract deployed. | -| DeploySmartContract | `acs0.ContractDeploymentInput <#acs0.ContractDeploymentInput>` | `aelf.Address <#aelf.Address>` | Deploy a smart contract on chain and return the address of the contract deployed. | -| UpdateSmartContract | `acs0.ContractUpdateInput <#acs0.ContractUpdateInput>` | `aelf.Address <#aelf.Address>` | Update a smart contract on chain. | -| ProposeNewContract | `acs0.ContractDeploymentInput <#acs0.ContractDeploymentInput>` | `aelf.Hash <#aelf.Hash>` | Create a proposal to deploy a new contract and returns the id of the proposed contract. | -| ProposeContractCodeCheck | `acs0.ContractCodeCheckInput <#acs0.ContractCodeCheckInput>` | `aelf.Hash <#aelf.Hash>` | Create a proposal to check the code of a contract and return the id of the proposed contract. | -| ProposeUpdateContract | `acs0.ContractUpdateInput <#acs0.ContractUpdateInput>` | `aelf.Hash <#aelf.Hash>` | Create a proposal to update the specified contract and return the id of the proposed contract. | -| ReleaseApprovedContract | `acs0.ReleaseContractInput <#acs0.ReleaseContractInput>` | `google.protobuf.Empty <#google.protobuf.Empty>` | Release the contract proposal which has been approved. | -| ReleaseCodeCheckedContract | `acs0.ReleaseContractInput <#acs0.ReleaseContractInput>` | `google.protobuf.Empty <#google.protobuf.Empty>` | Release the proposal which has passed the code check. | -| ValidateSystemContractAddress | `acs0.ValidateSystemContractAddressInput <#acs0.ValidateSystemContractAddressInput>` | `google.protobuf.Empty <#google.protobuf.Empty>` | Validate whether the input system contract exists. | -| SetContractProposerRequiredState | `google.protobuf.BoolValue <#google.protobuf.BoolValue>` | `google.protobuf.Empty <#google.protobuf.Empty>` | Set authority of contract deployment. | -| CurrentContractSerialNumber | `google.protobuf.Empty <#google.protobuf.Empty>` | `google.protobuf.Int64Value <#google.protobuf.Int64Value>` | Get the current serial number of genesis contract (corresponds to the serial number that will be given to the next deployed contract). | -| GetContractInfo | `aelf.Address <#aelf.Address>` | `acs0.ContractInfo <#acs0.ContractInfo>` | Get detailed information about the specified contract. | -| GetContractAuthor | `aelf.Address <#aelf.Address>` | `aelf.Address <#aelf.Address>` | Get author of the specified contract. | -| GetContractHash | `aelf.Address <#aelf.Address>` | `aelf.Hash <#aelf.Hash>` | Get the code hash of the contract about the specified address. | -| GetContractAddressByName | `aelf.Hash <#aelf.Hash>` | `aelf.Address <#aelf.Address>` | Get the address of a system contract by its name. | -| GetSmartContractRegistrationByAddress| `aelf.Address <#aelf.Address>` | `aelf.SmartContractRegistration <#aelf.SmartContractRegistration>` | Get the registration of a smart contract by its address. | -| GetSmartContractRegistrationByCodeHash | `aelf.Hash <#aelf.Hash>` | `aelf.SmartContractRegistration <#aelf.SmartContractRegistration>` | Get the registration of a smart contract by code hash. | -| DeployUserSmartContract | `acs0.ContractDeploymentInput <#acs0.ContractDeploymentInput>` | `acs0.DeployUserSmartContractOutput <#acs0.DeployUserSmartContractOutput>` | Deploy a user smart contract on chain and return the hash of the contract code. | -| UpdateUserSmartContract | `acs0.ContractUpdateInput <#acs0.ContractUpdateInput>` | `google.protobuf.Empty <#google.protobuf.Empty>` | Update a user smart contract on chain. | -| ReleaseApprovedUserSmartContract | `acs0.ReleaseContractInput <#acs0.ReleaseContractInput>` | `google.protobuf.Empty <#google.protobuf.Empty>` | Release the proposal which has passed the code check. | -| PerformDeployUserSmartContract | `acs0.ContractDeploymentInput <#acs0.ContractDeploymentInput>` | `aelf.Address <#aelf.Address>` | Perform user contract deployment. | -| PerformUpdateUserSmartContract | `acs0.ContractUpdateInput <#acs0.ContractUpdateInput>` | `google.protobuf.Empty <#google.protobuf.Empty>` | Perform user contract update. | -| SetContractAuthor | `acs0.SetContractAuthorInput <#acs0.SetContractAuthorInput>` | `google.protobuf.Empty <#google.protobuf.Empty>` | Set author of the specified contract. | - - -## Types - -
- -acs0.AuthorUpdated -''''''''''''''''''' - -| Field | Type | Description | Label | -|-------------|-----------------------------------|----------------------------------------------|---------| -| address | `aelf.address <#aelf.address>` | The byte array of the contract code. | | -| old_author | `aelf.address <#aelf.address>` | The category of contract code(0: C#). | | -| CrossChainCreateToken | `aelf.address <#aelf.address>` | Indicates if the contract is the system contract. | | - -
- -acs0.CodeCheckRequired -^^^^^^^^^^^^^^^^^^^^^^ - -| Field | Type | Description | Label | -|---------------------------------|------------------------------|----------------------------------------------------------|---------| -| code | `bytes <#bytes>` | The byte array of the contract code. | | -| proposed_contract_input_hash | `aelf.Hash <#aelf.Hash>` | The id of the proposed contract. | | -| category | `sint32 <#sint32>` | The category of contract code(0: C#). | | -| is_system_contract | `bool <#bool>` | Indicates if the contract is the system contract. | | -| is_user_contract | `bool <#bool>` | Indicates if the contract is the user contract. | | - -
- -acs0.CodeUpdated -^^^^^^^^^^^^^^^^ - -| Field | Type | Description | Label | -|------------------|------------------------------------|-----------------------------------------|---------| -| address | `aelf.Address <#aelf.Address>` | The address of the updated contract. | | -| old_code_hash | `aelf.Hash <#aelf.Hash>` | The byte array of the old contract code.| | -| new_code_hash | `aelf.Hash <#aelf.Hash>` | The byte array of the new contract code.| | -| version | `int32 <#int32>` | The version of the current contract. | | - -
- -acs0.ContractCodeCheckInput -^^^^^^^^^^^^^^^^^^^^^^^^^^^ -| Field | Type | Description | Label | -|-------------------------------|------------------------------|-----------------------------------------------------------------------------|---------| -| contract_input | `bytes <#bytes>` | The byte array of the contract code to be checked. | | -| is_contract_deployment | `bool <#bool>` | Whether the input contract is to be deployed or updated. | | -| code_check_release_method | `string <#string>` | Method to call after code check complete(DeploySmartContract or UpdateSmartContract). | | -| proposed_contract_input_hash | `aelf.Hash <#aelf.Hash>` | The id of the proposed contract. | | -| category | `sint32 <#sint32>` | The category of contract code(0: C#). | | -| is_system_contract | `bool <#bool>` | Indicates if the contract is the system contract. | | - -
- -acs0.ContractDeployed -^^^^^^^^^^^^^^^^^^^^^ +Contracts using ACS0 need to implement these methods: + +### Methods + +| Method Name | Request | Response | Description | +|------------------------------------|-------------------------------------|-----------------------------------|--------------------------------------------------| +| DeploySystemSmartContract | `acs0.SystemContractDeploymentInput`| `aelf.Address` | Deploys a system smart contract and returns its address. | +| DeploySmartContract | `acs0.ContractDeploymentInput` | `aelf.Address` | Deploys a smart contract and returns its address. | +| UpdateSmartContract | `acs0.ContractUpdateInput` | `aelf.Address` | Updates a smart contract. | +| ProposeNewContract | `acs0.ContractDeploymentInput` | `aelf.Hash` | Creates a proposal to deploy a new contract and returns its ID. | +| ProposeContractCodeCheck | `acs0.ContractCodeCheckInput` | `aelf.Hash` | Creates a proposal to check contract code and returns its ID. | +| ProposeUpdateContract | `acs0.ContractUpdateInput` | `aelf.Hash` | Creates a proposal to update a contract and returns its ID. | +| ReleaseApprovedContract | `acs0.ReleaseContractInput` | `google.protobuf.Empty` | Releases an approved contract proposal. | +| ReleaseCodeCheckedContract | `acs0.ReleaseContractInput` | `google.protobuf.Empty` | Releases a proposal that passed the code check. | +| ValidateSystemContractAddress | `acs0.ValidateSystemContractAddressInput` | `google.protobuf.Empty` | Validates if the input system contract exists. | +| SetContractProposerRequiredState | `google.protobuf.BoolValue` | `google.protobuf.Empty` | Sets contract deployment authority. | +| CurrentContractSerialNumber | `google.protobuf.Empty` | `google.protobuf.Int64Value` | Gets the current serial number of the genesis contract. | +| GetContractInfo | `aelf.Address` | `acs0.ContractInfo` | Gets information about a contract. | +| GetContractAuthor | `aelf.Address` | `aelf.Address` | Gets the author of a contract. | +| GetContractHash | `aelf.Address` | `aelf.Hash` | Gets the code hash of a contract by address. | +| GetContractAddressByName | `aelf.Hash` | `aelf.Address` | Gets the address of a system contract by name. | +| GetSmartContractRegistrationByAddress | `aelf.Address` | `aelf.SmartContractRegistration` | Gets the registration of a smart contract by address. | +| GetSmartContractRegistrationByCodeHash | `aelf.Hash` | `aelf.SmartContractRegistration` | Gets the registration of a smart contract by code hash. | +| DeployUserSmartContract | `acs0.ContractDeploymentInput` | `acs0.DeployUserSmartContractOutput` | Deploys a user smart contract and returns the contract code hash. | +| UpdateUserSmartContract | `acs0.ContractUpdateInput` | `google.protobuf.Empty` | Updates a user smart contract. | +| ReleaseApprovedUserSmartContract | `acs0.ReleaseContractInput` | `google.protobuf.Empty` | Releases a proposal that passed the code check. | +| PerformDeployUserSmartContract | `acs0.ContractDeploymentInput` | `aelf.Address` | Deploys a user contract. | +| PerformUpdateUserSmartContract | `acs0.ContractUpdateInput` | `google.protobuf.Empty` | Updates a user contract. | +| SetContractAuthor | `acs0.SetContractAuthorInput` | `google.protobuf.Empty` | Sets the author of a contract. | + +### Types + +#### acs0.AuthorUpdated + +| Field | Type | Description | +|--------------|--------------|----------------------------------| +| `address` | `aelf.address` | Contract code byte array. | +| `old_author` | `aelf.address` | Contract code category (0: C#). | + +#### acs0.CodeCheckRequired + +| Field | Type | Description | +|-------------------------------|--------------|--------------------------------| +| `code` | `bytes` | Contract code byte array. | +| `proposed_contract_input_hash`| `aelf.Hash` | Proposed contract ID. | +| `category` | `sint32` | Contract code category (0: C#).| +| `is_system_contract` | `bool` | Is it a system contract? | +| `is_user_contract` | `bool` | Is it a user contract? | + +#### acs0.CodeUpdated + +| Field | Type | Description | +|-----------------|--------------|--------------------------------| +| `address` | `aelf.Address` | Contract address. | +| `old_code_hash` | `aelf.Hash` | Old contract code byte array. | +| `new_code_hash` | `aelf.Hash` | New contract code byte array. | +| `version` | `int32` | Contract version. | + +### acs0.ContractCodeCheckInput# + +| Field | Type | Description | +|-------------------------------|--------------|-------------------------------------------------------| +| `contract_input` | `bytes` | Contract code byte array. | +| `is_contract_deployment` | `bool` | Is the contract being deployed or updated? | +| `code_check_release_method` | `string` | Method to call after code check (DeploySmartContract or UpdateSmartContract). | +| `proposed_contract_input_hash`| `aelf.Hash` | Proposed contract ID. | +| `category` | `sint32` | Contract code category (0: C#). | +| `is_system_contract` | `bool` | Is it a system contract? | + +#### acs0.ContractDeployed + +| Field | Type | Description | +|---------------------|--------------|----------------------------------| +| `author` | `aelf.Address` | Contract author. | +| `code_hash` | `aelf.Hash` | Contract code hash. | +| `address` | `aelf.Address` | Contract address. | +| `version` | `int32` | Contract version. | +| `name` | `aelf.Hash` | Contract name (must be unique). | +| `contract_version` | `string` | Contract version. | + +#### acs0.ContractDeploymentInput + +| Field | Type | Description | +|-----------|---------|------------------------------------| +| `category`| `sint32`| Contract code category (0: C#). | +| `code` | `bytes` | Contract code byte array. | + +#### acs0.DeployUserSmartContractOutput + +| Field | Type | Description | +|------------|------------|---------------------------------| +| `code_hash`| `aelf.Hash`| Deployed/updated contract code hash. | + +#### acs0.ContractInfo + +| Field | Type | Description | +|--------------------|--------------|----------------------------------| +| `serial_number` | `int64` | Contract serial number. | +| `author` | `aelf.Address` | Contract author. | +| `category` | `sint32` | Contract code category (0: C#). | +| `code_hash` | `aelf.Hash` | Contract code hash. | +| `is_system_contract`| `bool` | Is it a system contract? | +| `version` | `int32` | Contract version. | +| `contract_version` | `string` | Contract version. | +| `contract_type` | `string` | Contract type. | +| `deployed_by` | `aelf.Address` | Deployer address. | +| `deployed_on` | `google.protobuf.Timestamp` | Deployment time. | + +#### acs0.ContractUpdateInput + +| Field | Type | Description | +|---------------------|--------------|----------------------------------| +| `address` | `aelf.Address` | Contract address. | +| `code` | `bytes` | Contract code byte array. | +| `category` | `sint32` | Contract code category (0: C#). | +| `is_system_contract`| `bool` | Is it a system contract? | +| `is_user_contract` | `bool` | Is it a user contract? | + +#### acs0.ReleaseContractInput + +| Field | Type | Description | +|-------------|------------|--------------------------------| +| `proposal_id` | `aelf.Hash` | Proposal ID to be released. | -| Field | Type | Description | Label | -|----------------------|------------------------------------|------------------------------------------------------|---------| -| author | `aelf.Address <#aelf.Address>` | The author of the contract, this is the person who deployed the contract. | | -| code_hash | `aelf.Hash <#aelf.Hash>` | The hash of the contract code. | | -| address | `aelf.Address <#aelf.Address>` | The address of the contract. | | -| version | `int32 <#int32>` | The version of the current contract. | | -| Name | `aelf.Hash <#aelf.Hash>` | The name of the contract. It has to be unique. | | -| contract_version | `string <#string>` | The version of the current contract. | +#### acs0.SetContractAuthorInput -
+| Field | Type | Description | +|-----------------|--------------|----------------------------------| +| `address` | `aelf.Address` | Contract address. | +| `author` | `aelf.Address` | New author address. | +#### acs0.SystemContractDeploymentInput + +| Field | Type | Description | +|-----------------|--------------|----------------------------------| +| `category` | `sint32` | Contract code category (0: C#). | +| `code` | `bytes` | Contract code byte array. | +| `name` | `aelf.Hash` | Contract name (must be unique). | -acs0.ContractDeploymentInput -^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +#### acs0.ValidateSystemContractAddressInput + +| Field | Type | Description | +|------------------------|--------------|----------------------------------| +| `system_contract_hash_name` | `aelf.Hash` | Contract name hash. | +| `address` | `aelf.Address` | Contract address. | -| Field | Type | Description | Label | -|----------|-----------------------|-----------------------------------------|---------| -| category | `sint32 <#sint32>` | The category of contract code(0: C#). | | -| code | `bytes <#bytes>` | The byte array of the contract code. | | +#### aelf.Address -
+| Field | Type | Description | +|-----------|---------|----------------------------| +| `value` | `bytes` | Address value in bytes. | -acs0.DeployUserSmartContractOutput -''''''''''''''''''''''''''''''''''' +#### aelf.BinaryMerkleTree -| Field | Type | Description | Label | -|------------|------------------------|---------------------------------------------|---------| -| code_hash | `aelf.Hash <#aelf.Hash>` | The deployed or updated contract code hash. | | +| Field | Type | Description | +|-------------|----------|----------------------------------| +| `nodes` | `Hash` | Leaf nodes. | +| `root` | `Hash` | Root node hash. | +| `leaf_count`| `int32` | Number of leaf nodes. | -
+#### aelf.Hash -acs0.ContractInfo -^^^^^^^^^^^^^^^^^ +| Field | Type | Description | +|-----------|---------|----------------------------| +| `value` | `bytes` | Hash value in bytes. | -| Field | Type | Description | Label | -|--------------------|-------------------------|-----------------------------------------------------------------------------|---------| -| serial_number | `int64 <#int64>` | The serial number of the contract. | | -| author | `aelf.Address <#aelf.Address>` | The author of the contract, this is the person who deployed the contract. | | -| category | `sint32 <#sint32>` | The category of contract code(0: C#). | | -| code_hash | `aelf.Hash <#aelf.Hash>` | The hash of the contract code. | | -| is_system_contract | `bool <#bool>` | Whether it is a system contract. | | -| version | `int32 <#int32>` | The version of the current contract. | | -| contract_version | `string <#string>` | The version of the current contract. | | -| is_user_contract | `bool <#bool>` | Indicates if the contract is the user contract. | | +#### aelf.LogEvent -
+| Field | Type | Description | +|-------------|----------|----------------------------------| +| `address` | `Address`| Contract address. | +| `name` | `string` | Log event name. | +| `indexed` | `bytes` | Indexed data for bloom filter. | +| `non_indexed`| `bytes` | Non-indexed data. | -acs0.ContractProposed -^^^^^^^^^^^^^^^^^^^^^ +#### aelf.MerklePath -| Field | Type | Description | Label | -|---------------------------------|-------------------------|------------------------------------|---------| -| proposed_contract_input_hash | `aelf.Hash <#aelf.Hash>` | The id of the proposed contract. | | +| Field | Type | Description | +|----------------------|-----------------|----------------------------------| +| `merkle_path_nodes` | `MerklePathNode`| Merkle path nodes. | -
+#### aelf.MerklePathNode -acs0.ContractUpdateInput -^^^^^^^^^^^^^^^^^^^^^^^^ +| Field | Type | Description | +|--------------------|----------|--------------------------------| +| `hash` | `Hash` | Node hash. | +| `is_left_child_node`| `bool` | Is it a left child node? | + +#### aelf.SInt32Value + +| Field | Type | Description | +|---------|---------|------------------------------| +| `value` | `sint32`| Signed 32-bit integer value. | -| Field | Type | Description | Label | -|----------|-------------------------|--------------------------------------------------|---------| -| address | `aelf.Address <#aelf.Address>` | The contract address that needs to be updated. | | -| code | `bytes <#bytes>` | The byte array of the new contract code. | | +#### aelf.SInt64Value + +| Field | Type | Description | +|---------|---------|------------------------------| +| `value` | `sint64`| Signed 64-bit integer value. | -
+#### aelf.ScopedStatePath -acs0.SetContractAuthorInput -''''''''''''''''''''''''''''' +| Field | Type | Description | +|-----------|---------|------------------------------------| +| `address` | `Address` | Scope address (contract address). | +| `path` | `StatePath` | Contract state path. | -| Field | Type | Description | Label | -|-------------------|-------------------------|------------------------------------------------------|---------| -| contract_address | `aelf.Address <#aelf.Address>` | The author's contract address needs to be updated. | | -| new_author | `aelf.Address <#aelf.Address>` | The new contract author. | | +#### aelf.SmartContractRegistration -
+| Field | Type | Description | +|--------------------|----------|----------------------------------| +| `category` | `sint32` | Contract code category (0: C#). | +| `code` | `bytes` | Contract code byte array. | +| `code_hash` | `Hash` | Contract code hash. | +| `is_system_contract`| `bool` | Is it a system contract? | +| `version` | `int32` | Contract version. | -acs0.ReleaseContractInput -^^^^^^^^^^^^^^^^^^^^^^^^^ +#### aelf.StatePath -| Field | Type | Description | Label | -|---------------------------------|-------------------------|------------------------------------|---------| -| proposal_id | `aelf.Hash <#aelf.Hash>` | The hash of the proposal. | | -| proposed_contract_input_hash | `aelf.Hash <#aelf.Hash>` | The id of the proposed contract. | | +| Field | Type | Description | +|---------|---------|--------------------------------------| +| `parts` | `string`| State path parts. | -
+#### aelf.Transaction -acs0.SystemContractDeploymentInput -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +| Field | Type | Description | +|------------------|--------------|------------------------------------| +| `from` | `Address` | Sender address. | +| `to` | `Address` | Contract address. | +| `ref_block_number`| `int64` | Referenced block height. | +| `ref_block_prefix`| `bytes` | Referenced block hash prefix. | +| `method_name` | `string` | Smart contract method name. | +| `params` | `bytes` | Smart contract method parameters. | +| `signature` | `bytes` | Transaction signature. | -| Field | Type | Description | Label | -|--------------------------------|---------------------------------------------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------|---------| -| category | `sint32 <#sint32>` | The category of contract code(0: C#). | | -| code | `bytes <#bytes>` | The byte array of the contract code. | | -| name | `aelf.Hash <#aelf.Hash>` | The name of the contract. It has to be unique. | | -| transaction_method_call_list | `SystemContractDeploymentInput.SystemTransactionMethodCallList <#acs0.SystemContractDeploymentInput.SystemTransactionMethodCallList>` | An initial list of transactions for the system contract, which is executed in sequence when the contract is deployed. | +#### aelf.TransactionExecutingStateSet -
+| Field | Type | Description | +|---------|----------------------------------|---------------------------------| +| `writes`| `TransactionExecutingStateSet.WritesEntry`| Changed states. | +| `reads` | `TransactionExecutingStateSet.ReadsEntry` | Read states. | +| `deletes`| `TransactionExecutingStateSet.DeletesEntry` | Deleted states. | -acs0.SystemContractDeploymentInput.SystemTransactionMethodCall -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +#### aelf.TransactionExecutingStateSet.DeletesEntry -| Field | Type | Description | Label | -|---------------|------------------------|-------------------------------------------|---------| -| method_name | `string <#string>` | The method name of system transaction. | | -| params | `bytes <#bytes>` | The params of system transaction method. | | +| Field | Type | Description | +|---------|---------|---------------------------| +| `key` | `string`| State key. | +| `value` | `bool` | Deletion state (true/false).| -
+#### aelf.TransactionExecutingStateSet.ReadsEntry -acs0.SystemContractDeploymentInput.SystemTransactionMethodCallList -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +| Field | Type | Description | +|---------|---------|---------------------------| +| `key` | `string`| State key. | +| `value` | `bool` | Read state (true/false). | -| Field | Type | Description | Label | -|-------|---------------------------------------------------------------------------------------------------------------------------|---------------------------------------|------------| -| value | `SystemContractDeploymentInput.SystemTransactionMethodCall <#acs0.SystemContractDeploymentInput.SystemTransactionMethodCall>` | The list of system transactions. | repeated | +#### aelf.TransactionExecutingStateSet.WritesEntry -
+| Field | Type | Description | +|---------|---------|---------------------------| +| `key` | `string`| State key. | +| `value` | `bytes` | Written state value. | -acs0.ValidateSystemContractAddressInput -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +#### aelf.TransactionResult -| Field | Type | Description | Label | -|------------------------------|--------------------------------|------------------------------------|---------| -| system_contract_hash_name | `aelf.Hash <#aelf.Hash>` | The name hash of the contract. | | -| address | `aelf.Address <#aelf.Address>` | The address of the contract. | | +| Field | Type | Description | +|-----------------|--------------|------------------------------------| +| `transaction_id`| `Hash` | Transaction ID. | +| `status` | `TransactionResultStatus` | Transaction result status. | +| `logs` | `LogEvent` | Log events. | +| `bloom` | `bytes` | Bloom filter for logs. | +| `return_value` | `bytes` | Transaction execution return value.| +| `block_number` | `int64` | Block height. | +| `block_hash` | `Hash` | Block hash. | +| `error` | `string` | Error message. | -
+#### aelf.TransactionResultStatus -aelf.Address -^^^^^^^^^^^^ - -| Field | Type | Description | Label | -|-------|----------------------|---------------|---------| -| value | `bytes <#bytes>` | | | - -
- -aelf.BinaryMerkleTree -^^^^^^^^^^^^^^^^^^^^^ - -| Field | Type | Description | Label | -|-------------|---------------------|------------------------|------------| -| nodes | `Hash <#aelf.Hash>` | The leaf nodes. | repeated | -| root | `Hash <#aelf.Hash>` | The root node hash. | | -| leaf_count | `int32 <#int32>` | The count of leaf node.| | - -
- -aelf.Hash -^^^^^^^^^ - -| Field | Type | Description | Label | -|-------|--------------------|---------------|---------| -| value | `bytes <#bytes>` | | | - -
- -aelf.LogEvent -^^^^^^^^^^^^^ - -| Field | Type | Description | Label | -|-------------|---------------------------|--------------------------------------|------------| -| address | `Address <#aelf.Address>` | The contract address. | | -| name | `string <#string>` | The name of the log event. | | -| indexed | `bytes <#bytes>` | The indexed data, used to calculate bloom. | repeated | -| non_indexed | `bytes <#bytes>` | The non indexed data. | | - -
- -aelf.MerklePath -^^^^^^^^^^^^^^^ - -| Field | Type | Description | Label | -|-------------------|-------------------------------------|------------------------------|------------| -| merkle_path_nodes | `MerklePathNode <#aelf.MerklePathNode>` | The merkle path nodes. | repeated | - -
- -aelf.MerklePathNode -^^^^^^^^^^^^^^^^^^^ - -| Field | Type | Description | Label | -|-----------------------|--------------------|---------------------|---------| -| hash | `Hash <#aelf.Hash>`| The node hash. | | -| is_left_child_node | `bool <#bool>` | Whether it is a left child node. | | - -
- -aelf.SInt32Value -^^^^^^^^^^^^^^^^ - -| Field | Type | Description | Label | -|-------|---------------------|---------------|---------| -| value | `sint32 <#sint32>` | | | - -
- -aelf.SInt64Value -^^^^^^^^^^^^^^^^ - -| Field | Type | Description | Label | -|-------|---------------------|---------------|---------| -| value | `sint64 <#sint64>` | | | - -
- -aelf.ScopedStatePath -^^^^^^^^^^^^^^^^^^^^ - -| Field | Type | Description | Label | -|---------|---------------------------------|----------------------------------------------|---------| -| address | `Address <#aelf.Address>` | The scope address, which will be the contract address. | | -| path | `StatePath <#aelf.StatePath>` | The path of contract state. | | - -
- -aelf.SmartContractRegistration -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -| Field | Type | Description | Label | -|---------------------|-----------------------|-------------------------------------------|---------| -| category | `sint32 <#sint32>` | The category of contract code(0: C#). | | -| code | `bytes <#bytes>` | The byte array of the contract code. | | -| code_hash | `Hash <#aelf.Hash>` | The hash of the contract code. | | -| is_system_contract | `bool <#bool>` | Whether it is a system contract. | | -| version | `int32 <#int32>` | The version of the current contract. | | - -
- -aelf.StatePath -^^^^^^^^^^^^^^ - -| Field | Type | Description | Label | -|---------|----------------------|---------------------------------------|------------| -| parts | `string <#string>` | The partial path of the state path. | repeated | - -
- -aelf.Transaction -^^^^^^^^^^^^^^^^ - -| Field | Type | Description | Label | -|---------------------|-------------------------------|-----------------------------------------------------------------------------------------------------------|---------| -| from | `Address <#aelf.Address>` | The address of the sender of the transaction. | | -| to | `Address <#aelf.Address>` | The address of the contract when calling a contract. | | -| ref_block_number | `int64 <#int64>` | The height of the referenced block hash. | | -| ref_block_prefix | `bytes <#bytes>` | The first four bytes of the referenced block hash. | | -| method_name | `string <#string>` | The name of a method in the smart contract at the To address. | | -| params | `bytes <#bytes>` | The parameters to pass to the smart contract method. | | -| signature | `bytes <#bytes>` | When signing a transaction it's actually a subset of the fields: from/to and the target method as well as the parameter that were given. It also contains the reference block number and prefix. | | - -
- -aelf.TransactionExecutingStateSet -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -| Field | Type | Description | Label | -|---------|------------------------------------------------------------------|-------------------------|------------| -| writes | `TransactionExecutingStateSet.WritesEntry <#aelf.TransactionExecutingStateSet.WritesEntry>` | The changed states. | repeated | -| reads | `TransactionExecutingStateSet.ReadsEntry <#aelf.TransactionExecutingStateSet.ReadsEntry>` | The read states. | repeated | -| deletes | `TransactionExecutingStateSet.DeletesEntry <#aelf.TransactionExecutingStateSet.DeletesEntry>` | The deleted states. | repeated | - -
- -aelf.TransactionExecutingStateSet.DeletesEntry -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -| Field | Type | Description | Label | -|---------|----------------------|---------------|---------| -| key | `string <#string>` | | | -| value | `bool <#bool>` | | | - -
- -aelf.TransactionExecutingStateSet.ReadsEntry -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -| Field | Type | Description | Label | -|---------|----------------------|---------------|---------| -| key | `string <#string>` | | | -| value | `bool <#bool>` | | | - -
- -aelf.TransactionExecutingStateSet.WritesEntry -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -| Field | Type | Description | Label | -|---------|----------------------|---------------|---------| -| key | `string <#string>` | | | -| value | `bytes <#bytes>` | | | - -
- -aelf.TransactionResult -^^^^^^^^^^^^^^^^^^^^^^ - -| Field | Type | Description | Label | -|-------------------|-------------------------------|---------------------------------------------------------------------------------------------------|------------| -| transaction_id | `Hash <#aelf.Hash>` | The transaction id. | | -| status | `TransactionResultStatus <#aelf.TransactionResultStatus>` | The transaction result status. | | -| logs | `LogEvent <#aelf.LogEvent>` | The log events. | repeated | -| bloom | `bytes <#bytes>` | Bloom filter for transaction logs. A transaction log event can be defined in the contract and stored in the bloom filter after the transaction is executed. | | -| return_value | `bytes <#bytes>` | The return value of the transaction execution. | | -| block_number | `int64 <#int64>` | The height of the block hat packages the transaction. | | -| block_hash | `Hash <#aelf.Hash>` | The hash of the block hat packages the transaction. | | -| error | `string <#string>` | Failed execution error message. | | - -
- -aelf.TransactionResultStatus -^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -| Name | Number | Description | -|--------------------------|----------|-----------------------------------------------------------------------------------------------| -| NOT_EXISTED | 0 | The execution result of the transaction does not exist. | -| PENDING | 1 | The transaction is in the transaction pool waiting to be packaged. | -| FAILED | 2 | Transaction execution failed. | -| MINED | 3 | The transaction was successfully executed and successfully packaged into a block. | -| CONFLICT | 4 | When executed in parallel, there are conflicts with other transactions. | -| PENDING_VALIDATION | 5 | The transaction is waiting for validation. | -| NODE_VALIDATION_FAILED | 6 | Transaction validation failed. | - -Example -------- - -ACS0 declares methods for the scenes about contract deployment and update. AElf provides the implementation for ACS0, ``Genesis Contract``. -You can refer to the implementation of the :doc:`Genesis contract api<../smart-contract-api/genesis>`. +| Name | Value | Description | +|------------------------|-------|---------------------------------------------------------| +| `NOT_EXISTED` | 0 | Transaction result does not exist. | +| `PENDING` | 1 | Transaction in pool waiting to be packaged. | +| `FAILED` | 2 | Transaction execution failed. | +| `MINED` | 3 | Transaction successfully executed and packaged. | +| `CONFLICT` | 4 | Conflicts with other transactions during parallel execution.| +| `PENDING_VALIDATION` | 5 | Waiting for validation. | +| `NODE_VALIDATION_FAILED`| 6 | Validation failed. | + +## Example + +ACS0 defines methods for contract deployment and updates. AElf provides the Genesis Contract as an implementation of ACS0. \ No newline at end of file diff --git a/docs/Reference/ACS Introduction/ACS1 - Transaction Fee Standard.md b/docs/Reference/ACS Introduction/ACS1 - Transaction Fee Standard.md index 64e5992..f4b7f76 100644 --- a/docs/Reference/ACS Introduction/ACS1 - Transaction Fee Standard.md +++ b/docs/Reference/ACS Introduction/ACS1 - Transaction Fee Standard.md @@ -1,165 +1,158 @@ -ACS1 - Transaction Fee Standard +# ACS1 - Transaction Fee Standard +ACS1 handles transaction fees. -ACS1 manages transaction fees and is integrated into contracts needing fee management. +## Interface +Contracts using ACS1 must implement these methods: -### Interface - -Contracts inheriting ACS1 must implement the following APIs: - -#### Methods - -| Method Name | Request Type | Response Type | Description | -|--------------------------|--------------------------|-----------------------------|-------------------------------------------------------------| -| SetMethodFee | acs1.MethodFees | google.protobuf.Empty | Sets fees for a specified method, overriding existing fees. | -| ChangeMethodFeeController| AuthorityInfo | google.protobuf.Empty | Changes the method fee controller (default: parliament). | -| GetMethodFee | google.protobuf.StringValue | acs1.MethodFees | Retrieves method fee information by method name. | -| GetMethodFeeController | google.protobuf.Empty | AuthorityInfo | Retrieves the current method fee controller. | +### Methods +| Method Name | Request Type | Response Type | Description | +|--------------------------|--------------------------------|-------------------------|-----------------------------------------------------| +| SetMethodFee | `acs1.MethodFees` | `google.protobuf.Empty` | Sets the method fees for a method, overriding all fees. | +| ChangeMethodFeeController| `AuthorityInfo` | `google.protobuf.Empty` | Changes the method fee controller. Default is parliament. | +| GetMethodFee | `google.protobuf.StringValue` | `acs1.MethodFees` | Queries the fee for a method by name. | +| GetMethodFeeController | `google.protobuf.Empty` | `AuthorityInfo` | Queries the method fee controller. | ### Types - #### acs1.MethodFee - -| Field | Type | Description | Label | -|---------------|---------------|---------------------------------|-----------| -| symbol | string | Token symbol of the method fee. | | -| basic_fee | int64 | Fee amount to be charged. | | +| Field | Type | Description | +|------------|--------|-----------------------------------| +| symbol | string | The token symbol for the fee. | +| basic_fee | int64 | The fee amount. | #### acs1.MethodFees - -| Field | Type | Description | Label | -|---------------|---------------|---------------------------------|-----------| -| method_name | string | Name of the method. | | -| fees | MethodFee | List of fees for the method. | repeated | -| is_size_fee_free | bool | Indicates if size fee is free. | | +| Field | Type | Description | +|-----------------|------------|----------------------------------| +| method_name | string | The name of the method. | +| fees | MethodFee | List of fees. | +| is_size_fee_free| bool | Optional based on implementation.| #### AuthorityInfo - -| Field | Type | Description | Label | -|-------------------|--------------------|-------------------------------------------|-----------| -| contract_address | aelf.Address | Contract address of the controller. | | -| owner_address | aelf.Address | Address of the owner of the contract. | | +| Field | Type | Description | +|------------------|---------------|-----------------------------------| +| contract_address | aelf.Address | The controller's contract address.| +| owner_address | aelf.Address | The owner's address. | **Note:** Only system contracts on the main chain can implement ACS1. -### Usage - -In aelf, transaction fees are managed by ACS1 through a pre-transaction generated by FeeChargePreExecutionPlugin. This plugin charges transaction fees before processing the main transaction. - -The usage of ChargeTransactionFees method is implemented as below: - - ```cs - /// - /// Related transactions will be generated by acs1 pre-plugin service, - /// and will be executed before the origin transaction. - /// - /// - /// - public override BoolValue ChargeTransactionFees(ChargeTransactionFeesInput input) +## Usage +A pre-transaction, generated by FeeChargePreExecutionPlugin, charges the transaction fee before main processing. +```cs +/// +/// Related transactions will be generated by acs1 pre-plugin service, +/// and will be executed before the origin transaction. +/// +/// +/// +public override BoolValue ChargeTransactionFees(ChargeTransactionFeesInput input) +{ + // ... + // Record tx fee bill during current charging process. + var bill = new TransactionFeeBill(); + var fromAddress = Context.Sender; + var methodFees = Context.Call(input.ContractAddress, nameof(GetMethodFee), + new StringValue {Value = input.MethodName}); + var successToChargeBaseFee = true; + if (methodFees != null && methodFees.Fees.Any()) { - // ... - // Record tx fee bill during current charging process. - var bill = new TransactionFeeBill(); - var fromAddress = Context.Sender; - var methodFees = Context.Call(input.ContractAddress, nameof(GetMethodFee), - new StringValue {Value = input.MethodName}); - var successToChargeBaseFee = true; - if (methodFees != null && methodFees.Fees.Any()) - { - successToChargeBaseFee = ChargeBaseFee(GetBaseFeeDictionary(methodFees), ref bill); - } - var successToChargeSizeFee = true; - if (!IsMethodFeeSetToZero(methodFees)) + successToChargeBaseFee = ChargeBaseFee(GetBaseFeeDictionary(methodFees), ref bill); + } + var successToChargeSizeFee = true; + if (!IsMethodFeeSetToZero(methodFees)) + { + // Then also do not charge size fee. + successToChargeSizeFee = ChargeSizeFee(input, ref bill); + } + // Update balances. + foreach (var tokenToAmount in bill.FeesMap) + { + ModifyBalance(fromAddress, tokenToAmount.Key, -tokenToAmount.Value); + Context.Fire(new TransactionFeeCharged { - // Then also do not charge size fee. - successToChargeSizeFee = ChargeSizeFee(input, ref bill); - } - // Update balances. - foreach (var tokenToAmount in bill.FeesMap) + Symbol = tokenToAmount.Key, + Amount = tokenToAmount.Value + }); + if (tokenToAmount.Value == 0) { - ModifyBalance(fromAddress, tokenToAmount.Key, -tokenToAmount.Value); - Context.Fire(new TransactionFeeCharged - { - Symbol = tokenToAmount.Key, - Amount = tokenToAmount.Value - }); - if (tokenToAmount.Value == 0) - { - //Context.LogDebug(() => $"Maybe incorrect charged tx fee of {tokenToAmount.Key}: it's 0."); - } + //Context.LogDebug(() => $"Maybe incorrect charged tx fee of {tokenToAmount.Key}: it's 0."); } - return new BoolValue {Value = successToChargeBaseFee && successToChargeSizeFee}; } - ``` - -The usage of TransferTransactionFeesToFeeReceiver method is implemented as below: + return new BoolValue {Value = successToChargeBaseFee && successToChargeSizeFee}; +} +``` - ```cs - /// - /// Burn 10% of tx fees. - /// If Side Chain didn't set FeeReceiver, burn all. - /// - /// - /// - private void TransferTransactionFeesToFeeReceiver(string symbol, long totalAmount) +### Steps: +1. System calls `GetMethodFee` to determine the fee. +2. Checks if the balance is sufficient: + - If yes, the fee is billed. + - If no, the transaction is rejected. +3. If the method fee is not zero, the system charges a size fee based on the parameter's size. +4. After charging, an `TransactionFeeCharged` event is thrown, modifying the sender's balance. +5. The event is processed to calculate the total transaction fees in the block. +6. In the next block: + - 10% of the fees are destroyed. + - 90% goes to the dividend pool on the main chain and to the FeeReceiver on the side chain. +```cs +/// +/// Burn 10% of tx fees. +/// If Side Chain didn't set FeeReceiver, burn all. +/// +/// +/// +private void TransferTransactionFeesToFeeReceiver(string symbol, long totalAmount) +{ + Context.LogDebug(() => "Transfer transaction fee to receiver."); + if (totalAmount <= 0) return; + var burnAmount = totalAmount.Div(10); + if (burnAmount > 0) + Context.SendInline(Context.Self, nameof(Burn), new BurnInput + { + Symbol = symbol, + Amount = burnAmount + }); + var transferAmount = totalAmount.Sub(burnAmount); + if (transferAmount == 0) + return; + var treasuryContractAddress = + Context.GetContractAddressByName(SmartContractConstants.TreasuryContractSystemName); + if ( treasuryContractAddress!= null) { - Context.LogDebug(() => "Transfer transaction fee to receiver."); - if (totalAmount <= 0) return; - var burnAmount = totalAmount.Div(10); - if (burnAmount > 0) - Context.SendInline(Context.Self, nameof(Burn), new BurnInput - { - Symbol = symbol, - Amount = burnAmount - }); - var transferAmount = totalAmount.Sub(burnAmount); - if (transferAmount == 0) - return; - var treasuryContractAddress = - Context.GetContractAddressByName(SmartContractConstants.TreasuryContractSystemName); - if ( treasuryContractAddress!= null) + // Main chain would donate tx fees to dividend pool. + if (State.DividendPoolContract.Value == null) + State.DividendPoolContract.Value = treasuryContractAddress; + State.DividendPoolContract.Donate.Send(new DonateInput + { + Symbol = symbol, + Amount = transferAmount + }); + } + else + { + if (State.FeeReceiver.Value != null) { - // Main chain would donate tx fees to dividend pool. - if (State.DividendPoolContract.Value == null) - State.DividendPoolContract.Value = treasuryContractAddress; - State.DividendPoolContract.Donate.Send(new DonateInput + Context.SendInline(Context.Self, nameof(Transfer), new TransferInput { + To = State.FeeReceiver.Value, Symbol = symbol, - Amount = transferAmount + Amount = transferAmount, }); } else { - if (State.FeeReceiver.Value != null) - { - Context.SendInline(Context.Self, nameof(Transfer), new TransferInput - { - To = State.FeeReceiver.Value, - Symbol = symbol, - Amount = transferAmount, - }); - } - else + // Burn all! + Context.SendInline(Context.Self, nameof(Burn), new BurnInput { - // Burn all! - Context.SendInline(Context.Self, nameof(Burn), new BurnInput - { - Symbol = symbol, - Amount = transferAmount - }); - } + Symbol = symbol, + Amount = transferAmount + }); } } - ``` - -### Implementation - -Implement ACS1 by defining GetMethodFee to manage method-specific fees. Optionally, use MappedState for efficient fee management across methods. - -To set method fees, implement the `GetMethodFee` method. - -For methods `Foo1`, `Foo2`, `Bar1`, and `Bar2`, set fees to 1, 1, 2, and 2 ELF respectively. The fees can be hardcoded like this: +} +``` -```csharp +## Implementation +### Simple Implementation +Implement only `GetMethodFee` to set fixed fees for methods. +```cs public override MethodFees GetMethodFee(StringValue input) { if (input.Value == nameof(Foo1) || input.Value == nameof(Foo2)) @@ -196,10 +189,82 @@ public override MethodFees GetMethodFee(StringValue input) } ``` -### Test -Test ACS1 functionality by calling GetMethodFee and GetMethodFeeController to validate expected behavior. +### Recommended Implementation +1. Define a `MappedState` in the contract's State file for transaction fees. +```cs +public MappedState TransactionFees { get; set; } +``` +2. Modify `TransactionFees` in `SetMethodFee` and return the value in `GetMethodFee`. +```cs +public override MethodFees GetMethodFee(StringValue input) { + return State.TransactionFees[input.Value]; +} +``` +3. Add permission management to `SetMethodFee` to prevent arbitrary fee changes. +```cs +public SingletonState MethodFeeController { get; set; } +``` + +```cs +public override Empty SetMethodFee(MethodFees input) +{ + foreach (var symbolToAmount in input.Fees) + { + AssertValidToken(symbolToAmount.Symbol, symbolToAmount.BasicFee); + } + RequiredMethodFeeControllerSet(); + Assert(Context.Sender == State.MethodFeeController.Value.OwnerAddress, "Unauthorized to set method fee."); + State.TransactionFees[input.MethodName] = input; + return new Empty(); +} +``` +### Permission Management +1. Define a `SingletonState` with type `AuthorityInfo`. +```cs +private void RequiredMethodFeeControllerSet() +{ + if (State.MethodFeeController.Value != null) return; + if (State.ParliamentContract.Value == null) + { + State.ParliamentContract.Value = Context.GetContractAddressByName(SmartContractConstants.ParliamentContractSystemName); + } + var defaultAuthority = new AuthorityInfo(); + // Parliament Auth Contract maybe not deployed. + if (State.ParliamentContract.Value != null) + { + defaultAuthority.OwnerAddress = State.ParliamentContract.GetDefaultOrganizationAddress.Call(new Empty()); + defaultAuthority.ContractAddress = State.ParliamentContract.Value; + } + State.MethodFeeController.Value = defaultAuthority; +} +``` +2. Check the sender’s right by comparing its address with the owner’s address. +3. Implement permission checks to ensure only authorized changes. + +### Changing Authority +The authority for `SetMethodFee` can be changed through a transaction from the default parliament address. +```cs +public override Empty ChangeMethodFeeController(AuthorityInfo input) +{ + RequiredMethodFeeControllerSet(); + AssertSenderAddressWith(State.MethodFeeController.Value.OwnerAddress); + var organizationExist = CheckOrganizationExist(input); + Assert(organizationExist, "Invalid authority input."); + State.MethodFeeController.Value = input; + return new Empty(); +} +``` +```cs +public override AuthorityInfo GetMethodFeeController(Empty input) +{ + RequiredMethodFeeControllerSet(); + return State.MethodFeeController.Value; +} +``` -### Example +## Testing +Create ACS1’s Stub and call `GetMethodFee` and `GetMethodFeeController` to check the return values. -All aelf system contracts implement ACS1, providing a reference for implementation. \ No newline at end of file +## Example +All AElf system contracts implement ACS1 and can be used as references. \ No newline at end of file From d88a14b7f1e95442534b2e01dd5262c1e8230a8f Mon Sep 17 00:00:00 2001 From: vasmohi Date: Mon, 24 Jun 2024 12:49:52 +0530 Subject: [PATCH 06/16] Updated ACS2 - Parallel Execution Standard --- ...dard => ACS10 - Dividend Pool Standard.md} | 0 ...ACS11 - Cross Chain Consensus Standard.md} | 0 ...dard => ACS12 - User Contract Standard.md} | 0 .../ACS2 - Parallel Execution Standard | 114 ----- .../ACS2 - Parallel Execution Standard.md | 389 ++++++++++++++++++ ...d => ACS3 - Contract Proposal Standard.md} | 0 ... Standard => ACS4 - Consensus Standard.md} | 0 ... => ACS5 - Contract Threshold Standard.md} | 0 ...ion => ACS6 - Random Number Generation.md} | 0 ...tandard => ACS7 - Cross Chain Standard.md} | 0 ...ransaction Resource Token Fee Standard.md} | 0 ...S9 - Contract Profit Dividend Standard.md} | 0 12 files changed, 389 insertions(+), 114 deletions(-) rename docs/Reference/ACS Introduction/{ACS10 - Dividend Pool Standard => ACS10 - Dividend Pool Standard.md} (100%) rename docs/Reference/ACS Introduction/{ACS11 - Cross Chain Consensus Standard => ACS11 - Cross Chain Consensus Standard.md} (100%) rename docs/Reference/ACS Introduction/{ACS12 - User Contract Standard => ACS12 - User Contract Standard.md} (100%) delete mode 100644 docs/Reference/ACS Introduction/ACS2 - Parallel Execution Standard create mode 100644 docs/Reference/ACS Introduction/ACS2 - Parallel Execution Standard.md rename docs/Reference/ACS Introduction/{ACS3 - Contract Proposal Standard => ACS3 - Contract Proposal Standard.md} (100%) rename docs/Reference/ACS Introduction/{ACS4 - Consensus Standard => ACS4 - Consensus Standard.md} (100%) rename docs/Reference/ACS Introduction/{ACS5 - Contract Threshold Standard => ACS5 - Contract Threshold Standard.md} (100%) rename docs/Reference/ACS Introduction/{ACS6 - Random Number Generation => ACS6 - Random Number Generation.md} (100%) rename docs/Reference/ACS Introduction/{ACS7 - Cross Chain Standard => ACS7 - Cross Chain Standard.md} (100%) rename docs/Reference/ACS Introduction/{ACS8 - Transaction Resource Token Fee Standard => ACS8 - Transaction Resource Token Fee Standard.md} (100%) rename docs/Reference/ACS Introduction/{ACS9 - Contract Profit Dividend Standard => ACS9 - Contract Profit Dividend Standard.md} (100%) diff --git a/docs/Reference/ACS Introduction/ACS10 - Dividend Pool Standard b/docs/Reference/ACS Introduction/ACS10 - Dividend Pool Standard.md similarity index 100% rename from docs/Reference/ACS Introduction/ACS10 - Dividend Pool Standard rename to docs/Reference/ACS Introduction/ACS10 - Dividend Pool Standard.md diff --git a/docs/Reference/ACS Introduction/ACS11 - Cross Chain Consensus Standard b/docs/Reference/ACS Introduction/ACS11 - Cross Chain Consensus Standard.md similarity index 100% rename from docs/Reference/ACS Introduction/ACS11 - Cross Chain Consensus Standard rename to docs/Reference/ACS Introduction/ACS11 - Cross Chain Consensus Standard.md diff --git a/docs/Reference/ACS Introduction/ACS12 - User Contract Standard b/docs/Reference/ACS Introduction/ACS12 - User Contract Standard.md similarity index 100% rename from docs/Reference/ACS Introduction/ACS12 - User Contract Standard rename to docs/Reference/ACS Introduction/ACS12 - User Contract Standard.md diff --git a/docs/Reference/ACS Introduction/ACS2 - Parallel Execution Standard b/docs/Reference/ACS Introduction/ACS2 - Parallel Execution Standard deleted file mode 100644 index 9e41c89..0000000 --- a/docs/Reference/ACS Introduction/ACS2 - Parallel Execution Standard +++ /dev/null @@ -1,114 +0,0 @@ -ACS2 - Parallel Execution Standard - -ACS2 enables parallel execution of transactions by providing necessary resource information. - -### Interface - -A contract inheriting ACS2 must implement: - -#### Methods - -| Method Name | Request Type | Response Type | Description | -|------------------|---------------------|---------------------|-------------------------------------------------------| -| GetResourceInfo | aelf.Transaction | acs2.ResourceInfo | Retrieves resource dependencies for transaction exec. | - -### Types - -#### acs2.ResourceInfo - -| Field | Type | Description | Label | -|-------------------|----------------------|------------------------------------|-----------| -| write_paths | aelf.ScopedStatePath | State paths written during execution| repeated | -| read_paths | aelf.ScopedStatePath | State paths read during execution | repeated | -| non_parallelizable| bool | Indicates if transaction is non-parallelizable.| | - -#### Other Types (Omitted for brevity) - -Several other types like `aelf.Address`, `aelf.BinaryMerkleTree`, `aelf.LogEvent`, etc., are used within `acs2.ResourceInfo`. - -### Usage - -aelf uses State Paths to manage data storage, ensuring transaction grouping based on accessed paths for efficient parallel execution. - -### Implementation - -Token contract, for example, modifies balances through method Transfer. GetResourceInfo must notify ITransactionGrouper of accessed state paths. - -```cs -var args = TransferInput.Parser.ParseFrom(txn.Params); -var resourceInfo = new ResourceInfo -{ - Paths = - { - GetPath(nameof(TokenContractState.Balances), txn.From.ToString(), args.Symbol), - GetPath(nameof(TokenContractState.Balances), args.To.ToString(), args.Symbol), - } -}; -return resourceInfo; -``` - -### Test -Test transaction parallelizability using ITransactionGrouper's GroupAsync method with sample transactions. - - ```cs - var keyPair1 = SampleECKeyPairs.KeyPairs[0]; - var acs2DemoContractStub1 = GetACS2DemoContractStub(keyPair1); - var keyPair2 = SampleECKeyPairs.KeyPairs[1]; - var acs2DemoContractStub2 = GetACS2DemoContractStub(keyPair2); - - var transactionGrouper = Application.ServiceProvider.GetRequiredService(); - var blockchainService = Application.ServiceProvider.GetRequiredService(); - var chain = await blockchainService.GetChainAsync(); - - // Test parallel execution scenario - { - var groupedTransactions = await transactionGrouper.GroupAsync(new ChainContext - { - BlockHash = chain.BestChainHash, - BlockHeight = chain.BestChainHeight - }, new List - { - acs2DemoContractStub1.TransferCredits.GetTransaction(new TransferCreditsInput - { - To = Address.FromPublicKey(SampleECKeyPairs.KeyPairs[2].PublicKey), - Symbol = "ELF", - Amount = 1 - }), - acs2DemoContractStub2.TransferCredits.GetTransaction(new TransferCreditsInput - { - To = Address.FromPublicKey(SampleECKeyPairs.KeyPairs[3].PublicKey), - Symbol = "ELF", - Amount = 1 - }), - }); - groupedTransactions.Parallelizables.Count.ShouldBe(2); - } - - // Test non-parallel execution scenario - { - var groupedTransactions = await transactionGrouper.GroupAsync(new ChainContext - { - BlockHash = chain.BestChainHash, - BlockHeight = chain.BestChainHeight - }, new List - { - acs2DemoContractStub1.TransferCredits.GetTransaction(new TransferCreditsInput - { - To = Address.FromPublicKey(SampleECKeyPairs.KeyPairs[2].PublicKey), - Symbol = "ELF", - Amount = 1 - }), - acs2DemoContractStub2.TransferCredits.GetTransaction(new TransferCreditsInput - { - To = Address.FromPublicKey(SampleECKeyPairs.KeyPairs[2].PublicKey), - Symbol = "ELF", - Amount = 1 - }), - }); - groupedTransactions.Parallelizables.Count.ShouldBe(1); - } - ``` - -### Example - -For an example of implementing GetResourceInfo, refer to the MultiToken contract, ensuring transaction fees are considered for the keys involved. diff --git a/docs/Reference/ACS Introduction/ACS2 - Parallel Execution Standard.md b/docs/Reference/ACS Introduction/ACS2 - Parallel Execution Standard.md new file mode 100644 index 0000000..a0bea4d --- /dev/null +++ b/docs/Reference/ACS Introduction/ACS2 - Parallel Execution Standard.md @@ -0,0 +1,389 @@ +# ACS2 - Parallel Execution Standard +ACS2 helps with parallel transaction execution. + +## Interface +Contracts using ACS2 need to implement one method: + +### Methods +| Method Name | Request Type | Response Type | Description | +|------------------|-----------------------|----------------------|-----------------------------------------------------| +| GetResourceInfo | `aelf.Transaction` | `acs2.ResourceInfo` | Gets the resource info that the transaction execution depends on. | + +### Types +#### acs2.ResourceInfo +| Field | Type | Description | +|------------------|-------------------------|----------------------------------| +| write_paths | aelf.ScopedStatePath | State paths for writing. | +| read_paths | aelf.ScopedStatePath | State paths for reading. | +| non_parallelizable| bool | If the transaction isn't parallel.| + +#### aelf.Address +| Field | Type | Description | +|-------|-------|--------------------------| +| value | bytes | | + +#### aelf.BinaryMerkleTree +| Field | Type | Description | +|-------------|--------|--------------------| +| nodes | Hash | Leaf nodes. | +| root | Hash | Root node hash. | +| leaf_count | int32 | Count of leaf nodes.| + +#### aelf.Hash +| Field | Type | Description | +|-------|-------|--------------------------| +| value | bytes | | + +#### aelf.LogEvent +| Field | Type | Description | +|--------------|----------|---------------------| +| address | Address | Contract address. | +| name | string | Log event name. | +| indexed | bytes | Indexed data. | +| non_indexed | bytes | Non-indexed data. | + +#### aelf.MerklePath +| Field | Type | Description | +|-------------------|------------------|-------------------------| +| merkle_path_nodes | MerklePathNode | Merkle path nodes. | + +#### aelf.MerklePathNode +| Field | Type | Description | +|-------------------|-------|-------------------------| +| hash | Hash | Node hash. | +| is_left_child_node| bool | If it's a left child node.| + +#### aelf.SInt32Value +| Field | Type | Description | +|-------|-------|------------------------| +| value | sint32| | + +#### aelf.SInt64Value + +| Field | Type | Description | +|-------|-------|------------------------| +| value | sint64| | + +#### aelf.ScopedStatePath +| Field | Type | Description | +|----------|-------------|--------------------------------------| +| address | Address | Contract address. | +| path | StatePath | Path of contract state. | + +#### aelf.SmartContractRegistration +| Field | Type | Description | +|-------------------|---------|----------------------------------| +| category | sint32 | Contract code category (0: C#). | +| code | bytes | Contract code byte array. | +| code_hash | Hash | Contract code hash. | +| is_system_contract| bool | If it's a system contract. | +| version | int32 | Current contract version. | + +#### aelf.StatePath +| Field | Type | Description | +|-------|--------|--------------------------| +| parts | string | State path parts. | + +#### aelf.Transaction +| Field | Type | Description | +|------------------|--------|-----------------------------------| +| from | Address| Sender address. | +| to | Address| Contract address. | +| ref_block_number | int64 | Referenced block height. | +| ref_block_prefix | bytes | First 4 bytes of referenced block hash. | +| method_name | string | Method name in the contract. | +| params | bytes | Method parameters. | +| signature | bytes | Signature of the transaction. | + +#### aelf.TransactionExecutingStateSet +| Field | Type | Description | +|----------|-------------------------------------------|---------------------| +| writes | TransactionExecutingStateSet.WritesEntry | Changed states. | +| reads | TransactionExecutingStateSet.ReadsEntry | Read states. | +| deletes | TransactionExecutingStateSet.DeletesEntry | Deleted states. | + +#### aelf.TransactionExecutingStateSet.DeletesEntry +| Field | Type | Description | +|-------|--------|-------------------| +| key | string | | +| value | bool | | + +#### aelf.TransactionExecutingStateSet.ReadsEntry +| Field | Type | Description | +|-------|--------|-------------------| +| key | string | | +| value | bool | | + +#### aelf.TransactionExecutingStateSet.WritesEntry +| Field | Type | Description | +|-------|--------|-------------------| +| key | string | | +| value | bytes | | + +#### aelf.TransactionResult +| Field | Type | Description | +|----------------|-----------------------|-----------------------------------------------| +| transaction_id | Hash | Transaction ID. | +| status | TransactionResultStatus| Transaction result status. | +| logs | LogEvent | Log events. | +| bloom | bytes | Bloom filter for transaction logs. | +| return_value | bytes | Return value of the transaction execution. | +| block_number | int64 | Block height that packages the transaction. | +| block_hash | Hash | Block hash that packages the transaction. | +| error | string | Failed execution error message. | + +#### aelf.TransactionResultStatus + +| Name | Number | Description | +|-----------------------|--------|-----------------------------------------------------------| +| NOT_EXISTED | 0 | Transaction result does not exist. | +| PENDING | 1 | Transaction is waiting to be packaged. | +| FAILED | 2 | Transaction execution failed. | +| MINED | 3 | Transaction was successfully executed and packaged. | +| CONFLICT | 4 | Transaction has conflicts with other transactions. | +| PENDING_VALIDATION | 5 | Transaction is waiting for validation. | +| NODE_VALIDATION_FAILED| 6 | Transaction validation failed. | + +## Usage + +AElf uses a key-value database to store data. State Path determines the key for contract execution data. + +For example, a Token contract defines a balance property: +```cs +public MappedState Balances { get; set; } +``` + +To access the balance of an address (`2EM5uV6bSJh6xJfZTUa1pZpYsYcCUAdPvZvFUJzMDJEx3rbioz`) for a `Token contract` address (`Nmjj7noTpMqZ522j76SDsFLhiKkThv1u3d4TxqJMD8v89tWmE`), use its key in the database: +```cs +Nmjj7noTpMqZ522j76SDsFLhiKkThv1u3d4TxqJMD8v89tWmE/Balances/2EM5uV6bSJh6xJfZTUa1pZpYsYcCUAdPvZvFUJzMDJEx3rbioz/ELF +``` + +Parallel execution groups transactions by their State Paths. If two methods don’t access the same `StatePath`, they can be executed in parallel. + +If State Paths mismatch, the transaction is canceled and labeled as “cannot be grouped”. + +For more details, check the `ITransactionGrouper` and `IParallelTransactionExecutingService` code. + +## Implementation +Example: Token Contract +For the Transfer method, notify ITransactionGrouper via GetResourceInfo about the ELF balances of address A and B: +```cs +var args = TransferInput.Parser.ParseFrom(txn.Params); +var resourceInfo = new ResourceInfo +{ + Paths = + { + GetPath(nameof(TokenContractState.Balances), txn.From.ToString(), args.Symbol), + GetPath(nameof(TokenContractState.Balances), args.To.ToString(), args.Symbol), + } +}; +return resourceInfo; +``` + +The `GetPath` method forms a `ScopedStatePath` from key data: +```cs +private ScopedStatePath GetPath(params string[] parts) +{ + return new ScopedStatePath + { + Address = Context.Self, + Path = new StatePath + { + Parts = + { + parts + } + } + } +} +``` + +## Testing +Construct two transactions and pass them to `ITransactionGrouper` to test if they can run in parallel using `GroupAsync`. + +Prepare two stubs with different addresses: +```cs +var keyPair1 = SampleECKeyPairs.KeyPairs[0]; +var acs2DemoContractStub1 = GetACS2DemoContractStub(keyPair1); +var keyPair2 = SampleECKeyPairs.KeyPairs[1]; +var acs2DemoContractStub2 = GetACS2DemoContractStub(keyPair2); +``` + +```cs +var transactionGrouper = Application.ServiceProvider.GetRequiredService(); +var blockchainService = Application.ServiceProvider.GetRequiredService(); +var chain = await blockchainService.GetChainAsync(); +``` + +Check with transactionGrouper: +```cs +// Situation can be parallel executed. +{ + var groupedTransactions = await transactionGrouper.GroupAsync(new ChainContext + { + BlockHash = chain.BestChainHash, + BlockHeight = chain.BestChainHeight + }, new List + { + acs2DemoContractStub1.TransferCredits.GetTransaction(new TransferCreditsInput + { + To = Address.FromPublicKey(SampleECKeyPairs.KeyPairs[2].PublicKey), + Symbol = "ELF", + Amount = 1 + }), + acs2DemoContractStub2.TransferCredits.GetTransaction(new TransferCreditsInput + { + To = Address.FromPublicKey(SampleECKeyPairs.KeyPairs[3].PublicKey), + Symbol = "ELF", + Amount = 1 + }), + }); + groupedTransactions.Parallelizables.Count.ShouldBe(2); +} +// Situation cannot. +{ + var groupedTransactions = await transactionGrouper.GroupAsync(new ChainContext + { + BlockHash = chain.BestChainHash, + BlockHeight = chain.BestChainHeight + }, new List + { + acs2DemoContractStub1.TransferCredits.GetTransaction(new TransferCreditsInput + { + To = Address.FromPublicKey(SampleECKeyPairs.KeyPairs[2].PublicKey), + Symbol = "ELF", + Amount = 1 + }), + acs2DemoContractStub2.TransferCredits.GetTransaction(new TransferCreditsInput + { + To = Address.FromPublicKey(SampleECKeyPairs.KeyPairs[2].PublicKey), + Symbol = "ELF", + Amount = 1 + }), + }); + groupedTransactions.Parallelizables.Count.ShouldBe(1); +} +``` + +## Example +Refer to the `MultiToken contract` implementation for `GetResourceInfo`. Note that `Transfer` method needs to handle transaction fees along with keys. + + + + + + +ACS2 - Parallel Execution Standard + +ACS2 enables parallel execution of transactions by providing necessary resource information. + +### Interface + +A contract inheriting ACS2 must implement: + +#### Methods + +| Method Name | Request Type | Response Type | Description | +|------------------|---------------------|---------------------|-------------------------------------------------------| +| GetResourceInfo | aelf.Transaction | acs2.ResourceInfo | Retrieves resource dependencies for transaction exec. | + +### Types + +#### acs2.ResourceInfo + +| Field | Type | Description | Label | +|-------------------|----------------------|------------------------------------|-----------| +| write_paths | aelf.ScopedStatePath | State paths written during execution| repeated | +| read_paths | aelf.ScopedStatePath | State paths read during execution | repeated | +| non_parallelizable| bool | Indicates if transaction is non-parallelizable.| | + +#### Other Types (Omitted for brevity) + +Several other types like `aelf.Address`, `aelf.BinaryMerkleTree`, `aelf.LogEvent`, etc., are used within `acs2.ResourceInfo`. + +### Usage + +aelf uses State Paths to manage data storage, ensuring transaction grouping based on accessed paths for efficient parallel execution. + +### Implementation + +Token contract, for example, modifies balances through method Transfer. GetResourceInfo must notify ITransactionGrouper of accessed state paths. + +```cs +var args = TransferInput.Parser.ParseFrom(txn.Params); +var resourceInfo = new ResourceInfo +{ + Paths = + { + GetPath(nameof(TokenContractState.Balances), txn.From.ToString(), args.Symbol), + GetPath(nameof(TokenContractState.Balances), args.To.ToString(), args.Symbol), + } +}; +return resourceInfo; +``` + +### Test +Test transaction parallelizability using ITransactionGrouper's GroupAsync method with sample transactions. + + ```cs + var keyPair1 = SampleECKeyPairs.KeyPairs[0]; + var acs2DemoContractStub1 = GetACS2DemoContractStub(keyPair1); + var keyPair2 = SampleECKeyPairs.KeyPairs[1]; + var acs2DemoContractStub2 = GetACS2DemoContractStub(keyPair2); + + var transactionGrouper = Application.ServiceProvider.GetRequiredService(); + var blockchainService = Application.ServiceProvider.GetRequiredService(); + var chain = await blockchainService.GetChainAsync(); + + // Test parallel execution scenario + { + var groupedTransactions = await transactionGrouper.GroupAsync(new ChainContext + { + BlockHash = chain.BestChainHash, + BlockHeight = chain.BestChainHeight + }, new List + { + acs2DemoContractStub1.TransferCredits.GetTransaction(new TransferCreditsInput + { + To = Address.FromPublicKey(SampleECKeyPairs.KeyPairs[2].PublicKey), + Symbol = "ELF", + Amount = 1 + }), + acs2DemoContractStub2.TransferCredits.GetTransaction(new TransferCreditsInput + { + To = Address.FromPublicKey(SampleECKeyPairs.KeyPairs[3].PublicKey), + Symbol = "ELF", + Amount = 1 + }), + }); + groupedTransactions.Parallelizables.Count.ShouldBe(2); + } + + // Test non-parallel execution scenario + { + var groupedTransactions = await transactionGrouper.GroupAsync(new ChainContext + { + BlockHash = chain.BestChainHash, + BlockHeight = chain.BestChainHeight + }, new List + { + acs2DemoContractStub1.TransferCredits.GetTransaction(new TransferCreditsInput + { + To = Address.FromPublicKey(SampleECKeyPairs.KeyPairs[2].PublicKey), + Symbol = "ELF", + Amount = 1 + }), + acs2DemoContractStub2.TransferCredits.GetTransaction(new TransferCreditsInput + { + To = Address.FromPublicKey(SampleECKeyPairs.KeyPairs[2].PublicKey), + Symbol = "ELF", + Amount = 1 + }), + }); + groupedTransactions.Parallelizables.Count.ShouldBe(1); + } + ``` + +### Example + +For an example of implementing GetResourceInfo, refer to the MultiToken contract, ensuring transaction fees are considered for the keys involved. diff --git a/docs/Reference/ACS Introduction/ACS3 - Contract Proposal Standard b/docs/Reference/ACS Introduction/ACS3 - Contract Proposal Standard.md similarity index 100% rename from docs/Reference/ACS Introduction/ACS3 - Contract Proposal Standard rename to docs/Reference/ACS Introduction/ACS3 - Contract Proposal Standard.md diff --git a/docs/Reference/ACS Introduction/ACS4 - Consensus Standard b/docs/Reference/ACS Introduction/ACS4 - Consensus Standard.md similarity index 100% rename from docs/Reference/ACS Introduction/ACS4 - Consensus Standard rename to docs/Reference/ACS Introduction/ACS4 - Consensus Standard.md diff --git a/docs/Reference/ACS Introduction/ACS5 - Contract Threshold Standard b/docs/Reference/ACS Introduction/ACS5 - Contract Threshold Standard.md similarity index 100% rename from docs/Reference/ACS Introduction/ACS5 - Contract Threshold Standard rename to docs/Reference/ACS Introduction/ACS5 - Contract Threshold Standard.md diff --git a/docs/Reference/ACS Introduction/ACS6 - Random Number Generation b/docs/Reference/ACS Introduction/ACS6 - Random Number Generation.md similarity index 100% rename from docs/Reference/ACS Introduction/ACS6 - Random Number Generation rename to docs/Reference/ACS Introduction/ACS6 - Random Number Generation.md diff --git a/docs/Reference/ACS Introduction/ACS7 - Cross Chain Standard b/docs/Reference/ACS Introduction/ACS7 - Cross Chain Standard.md similarity index 100% rename from docs/Reference/ACS Introduction/ACS7 - Cross Chain Standard rename to docs/Reference/ACS Introduction/ACS7 - Cross Chain Standard.md diff --git a/docs/Reference/ACS Introduction/ACS8 - Transaction Resource Token Fee Standard b/docs/Reference/ACS Introduction/ACS8 - Transaction Resource Token Fee Standard.md similarity index 100% rename from docs/Reference/ACS Introduction/ACS8 - Transaction Resource Token Fee Standard rename to docs/Reference/ACS Introduction/ACS8 - Transaction Resource Token Fee Standard.md diff --git a/docs/Reference/ACS Introduction/ACS9 - Contract Profit Dividend Standard b/docs/Reference/ACS Introduction/ACS9 - Contract Profit Dividend Standard.md similarity index 100% rename from docs/Reference/ACS Introduction/ACS9 - Contract Profit Dividend Standard rename to docs/Reference/ACS Introduction/ACS9 - Contract Profit Dividend Standard.md From 1af349fb907f3bac75bac7532e889af853bc457f Mon Sep 17 00:00:00 2001 From: vasmohi Date: Mon, 24 Jun 2024 18:32:57 +0530 Subject: [PATCH 07/16] Updated ACS3 - Contract Proposal Standard --- .../ACS3 - Contract Proposal Standard.md | 357 ++++++++++++++++++ 1 file changed, 357 insertions(+) diff --git a/docs/Reference/ACS Introduction/ACS3 - Contract Proposal Standard.md b/docs/Reference/ACS Introduction/ACS3 - Contract Proposal Standard.md index e69de29..79b5f66 100644 --- a/docs/Reference/ACS Introduction/ACS3 - Contract Proposal Standard.md +++ b/docs/Reference/ACS Introduction/ACS3 - Contract Proposal Standard.md @@ -0,0 +1,357 @@ +# ACS3 - Contract Proposal Standard + +ACS3 is used when a method needs multiple approvals. Implement these methods for voting and approval: + +## Interface + +### Methods + +| Method Name | Request Type | Response Type | Description | +| ---------------------------------- | ---------------------------------------------- | ---------------------------- | ------------------------------------------------------------------------------------------------ | +| **CreateProposal** | acs3.CreateProposalInput | aelf.Hash | Creates a proposal for voting and returns the proposal ID. | +| **Approve** | aelf.Hash | google.protobuf.Empty | Approves a proposal by its ID. | +| **Reject** | aelf.Hash | google.protobuf.Empty | Rejects a proposal by its ID. | +| **Abstain** | aelf.Hash | google.protobuf.Empty | Abstains from voting on a proposal by its ID. | +| **Release** | aelf.Hash | google.protobuf.Empty | Releases a proposal by its ID, triggering the specified contract call. | +| **ChangeOrganizationThreshold** | acs3.ProposalReleaseThreshold | google.protobuf.Empty | Changes the proposal thresholds, affecting all current proposals. | +| **ChangeOrganizationProposerWhiteList** | acs3.ProposerWhiteList | google.protobuf.Empty | Changes the proposer whitelist for the organization. | +| **CreateProposalBySystemContract** | acs3.CreateProposalBySystemContractInput | aelf.Hash | Creates a proposal by system contracts and returns the proposal ID. | +| **ClearProposal** | aelf.Hash | google.protobuf.Empty | Removes a specified proposal. If the proposal is active, removal fails. | +| **GetProposal** | aelf.Hash | acs3.ProposalOutput | Retrieves a proposal by its ID. | +| **ValidateOrganizationExist** | aelf.Address | google.protobuf.BoolValue | Checks if an organization exists. | +| **ValidateProposerInWhiteList** | acs3.ValidateProposerInWhiteListInput | google.protobuf.BoolValue | Checks if the proposer is in the whitelist. | + +### Types + +#### acs3.CreateProposalBySystemContractInput +| Field | Type | Description | Label | +| --------------- | ---------------- | --------------------------------- | ------- | +| proposal_input | CreateProposalInput | Parameters for creating the proposal | | +| origin_proposer | aelf.Address | Address of the proposer | | + +#### acs3.CreateProposalInput +| Field | Type | Description | Label | +| -------------------- | -------------------------- | ------------------------------------- | ----- | +| contract_method_name | string | Method name to call after release | | +| to_address | aelf.Address | Contract address to call after release| | +| params | bytes | Parameters for the method call | | +| expired_time | google.protobuf.Timestamp | Proposal expiration time | | +| organization_address | aelf.Address | Organization address | | +| proposal_description_url | string | URL for proposal description | | +| token | aelf.Hash | Token for proposal ID generation | | + +#### acs3.OrganizationCreated +| Field | Type | Description | Label | +| ------------------- | ------------- | ------------------------ | ----- | +| organization_address| aelf.Address | Created organization address | | + +#### acs3.OrganizationHashAddressPair +| Field | Type | Description | Label | +| ------------------- | ------------- | ------------------------ | ----- | +| organization_hash | aelf.Hash | Organization ID | | +| organization_address| aelf.Address | Organization address | | + +#### acs3.OrganizationThresholdChanged +| Field | Type | Description | Label | +| ------------------------- | ------------------------ | ------------------------ | ----- | +| organization_address | aelf.Address | Organization address | | +| proposer_release_threshold| ProposalReleaseThreshold | New release threshold | | + +#### acs3.OrganizationWhiteListChanged +| Field | Type | Description | Label | +| ------------------- | ------------- | ------------------------ | ----- | +| organization_address| aelf.Address | Organization address | | +| proposer_white_list | ProposerWhiteList | New proposer whitelist | | + +#### acs3.ProposalCreated +| Field | Type | Description | Label | +| ------------------- | ------------- | ------------------------ | ----- | +| proposal_id | aelf.Hash | Created proposal ID | | +| organization_address| aelf.Address | Organization address | | + +#### acs3.ProposalOutput +| Field | Type | Description | Label | +| -------------------- | -------------------------- | ------------------------------------- | ----- | +| proposal_id | aelf.Hash | Proposal ID | | +| contract_method_name | string | Method name for release | | +| to_address | aelf.Address | Target contract address | | +| params | bytes | Release transaction parameters | | +| expired_time | google.protobuf.Timestamp | Proposal expiration date | | +| organization_address | aelf.Address | Organization address | | +| proposer | aelf.Address | Proposer address | | +| to_be_released | bool | Indicates if releasable | | +| approval_count | int64 | Approval count | | +| rejection_count | int64 | Rejection count | | +| abstention_count | int64 | Abstention count | | + +#### acs3.ProposalReleaseThreshold +| Field | Type | Description | Label | +| -------------------------- | ----- | ------------------------------- | ----- | +| minimal_approval_threshold | int64 | Minimum approval threshold | | +| maximal_rejection_threshold| int64 | Maximum rejection threshold | | +| maximal_abstention_threshold | int64 | Maximum abstention threshold | | +| minimal_vote_threshold | int64 | Minimum vote threshold | | + +#### acs3.ProposalReleased +| Field | Type | Description | Label | +| ------------------- | ------------- | ------------------------ | ----- | +| proposal_id | aelf.Hash | Released proposal ID | | +| organization_address| aelf.Address | Organization address | | + +#### acs3.ProposerWhiteList +| Field | Type | Description | Label | +| ---------- | ------------- | ----------------- | -------- | +| proposers | aelf.Address | Proposer addresses| repeated | + +#### acs3.ReceiptCreated +| Field | Type | Description | Label | +| ------------------- | ------------------------- | ------------------------ | ----- | +| proposal_id | aelf.Hash | Proposal ID | | +| address | aelf.Address | Sender address | | +| receipt_type | string | Receipt type (Approve, Reject, Abstain) | | +| time | google.protobuf.Timestamp | Timestamp | | +| organization_address| aelf.Address | Organization address | | + +#### acs3.ValidateProposerInWhiteListInput +| Field | Type | Description | Label | +| ------------------- | ------------- | ------------------------ | ----- | +| proposer | aelf.Address | Proposer address | | +| organization_address| aelf.Address | Organization address | | + +## Implementation + +Assume there's only one organization in a contract, so no need to define the Organization type. Voters must use a token to vote. We'll focus on the core methods: CreateProposal, Approve, Reject, Abstain, and Release. + +### State Attributes +```cs +public MappedState Proposals { get; set; } +public SingletonState ProposalReleaseThreshold { get; set; } +``` + +- `Proposals` stores all proposal info. +- `ProposalReleaseThreshold` saves the requirements to release a proposal. + +### Initialization +Set the proposal release requirements when the contract initializes: +```cs +public override Empty Initialize(Empty input) +{ + State.TokenContract.Value = + Context.GetContractAddressByName(SmartContractConstants.TokenContractSystemName); + State.ProposalReleaseThreshold.Value = new ProposalReleaseThreshold + { + MinimalApprovalThreshold = 1, + MinimalVoteThreshold = 1 + }; + return new Empty(); +} +``` + +Requires at least one vote and one approval. + +### Create Proposal +Creates a proposal and stores it with its details. +```cs +public override Hash CreateProposal(CreateProposalInput input) +{ + var proposalId = Context.GenerateId(Context.Self, input.Token); + Assert(State.Proposals[proposalId] == null, "Proposal with same token already exists."); + State.Proposals[proposalId] = new ProposalInfo + { + ProposalId = proposalId, + Proposer = Context.Sender, + ContractMethodName = input.ContractMethodName, + Params = input.Params, + ExpiredTime = input.ExpiredTime, + ToAddress = input.ToAddress, + ProposalDescriptionUrl = input.ProposalDescriptionUrl + }; + return proposalId; +} +``` + +### Voting Methods + +#### Abstain +```cs +public override Empty Abstain(Hash input) +{ + Charge(); + var proposal = State.Proposals[input]; + if (proposal == null) + { + throw new AssertionException("Proposal not found."); + } + proposal.Abstentions.Add(Context.Sender); + State.Proposals[input] = proposal; + return new Empty(); +} +``` + +#### Approve +```cs +public override Empty Approve(Hash input) +{ + Charge(); + var proposal = State.Proposals[input]; + if (proposal == null) + { + throw new AssertionException("Proposal not found."); + } + proposal.Approvals.Add(Context.Sender); + State.Proposals[input] = proposal; + return new Empty(); +} +``` + +#### Reject +```cs +public override Empty Reject(Hash input) +{ + Charge(); + var proposal = State.Proposals[input]; + if (proposal == null) + { + throw new AssertionException("Proposal not found."); + } + proposal.Rejections.Add(Context.Sender); + State.Proposals[input] = proposal; + return new Empty(); +} +``` + +#### Charge +```cs +private void Charge() +{ + State.TokenContract.TransferFrom.Send(new TransferFromInput + { + From = Context.Sender, + To = Context.Self, + Symbol = Context.Variables.NativeSymbol, + Amount = 1_00000000 + }); +} +``` + +### Release Proposal +Releases a proposal if the vote count meets the threshold: +```cs +public override Empty Release(Hash input) +{ + var proposal = State.Proposals[input]; + if (proposal == null) + { + throw new AssertionException("Proposal not found."); + } + Assert(IsReleaseThresholdReached(proposal), "Didn't reach release threshold."); + Context.SendInline(proposal.ToAddress, proposal.ContractMethodName, proposal.Params); + return new Empty(); +} +private bool IsReleaseThresholdReached(ProposalInfo proposal) +{ + var isRejected = IsProposalRejected(proposal); + if (isRejected) + return false; + var isAbstained = IsProposalAbstained(proposal); + return !isAbstained && CheckEnoughVoteAndApprovals(proposal); +} +private bool IsProposalRejected(ProposalInfo proposal) +{ + var rejectionMemberCount = proposal.Rejections.Count; + return rejectionMemberCount > State.ProposalReleaseThreshold.Value.MaximalRejectionThreshold; +} +private bool IsProposalAbstained(ProposalInfo proposal) +{ + var abstentionMemberCount = proposal.Abstentions.Count; + return abstentionMemberCount > State.ProposalReleaseThreshold.Value.MaximalAbstentionThreshold; +} +private bool CheckEnoughVoteAndApprovals(ProposalInfo proposal) +{ + var approvedMemberCount = proposal.Approvals.Count; + var isApprovalEnough = + approvedMemberCount >= State.ProposalReleaseThreshold.Value.MinimalApprovalThreshold; + if (!isApprovalEnough) + return false; + var isVoteThresholdReached = + proposal.Abstentions.Concat(proposal.Approvals).Concat(proposal.Rejections).Count() >= + State.ProposalReleaseThreshold.Value.MinimalVoteThreshold; + return isVoteThresholdReached; +} +``` + +## Test +Add methods to a Dapp contract and test the proposal with these methods. + +### State Class +```cs +public StringState Slogan { get; set; } +public SingletonState
Organization { get; set; } +``` + +#### Set/Get Methods +```cs +public override StringValue GetSlogan(Empty input) +{ + return State.Slogan.Value == null ? new StringValue() : new StringValue {Value = State.Slogan.Value}; +} + +public override Empty SetSlogan(StringValue input) +{ + Assert(Context.Sender == State.Organization.Value, "No permission."); + State.Slogan.Value = input.Value; + return new Empty(); +} +``` + +#### Prepare a Stub +```cs +var keyPair = SampleECKeyPairs.KeyPairs[0]; +var acs3DemoContractStub = + GetTester(DAppContractAddress, keyPair); +``` + +#### Approve Token Transaction +```cs +var tokenContractStub = + GetTester( + GetAddress(TokenSmartContractAddressNameProvider.StringName), keyPair); +await tokenContractStub.Approve.SendAsync(new ApproveInput +{ + Spender = DAppContractAddress, + Symbol = "ELF", + Amount = long.MaxValue +}); +``` + +#### Create and Test Proposal +Create a proposal to change the Slogan to "AElf": +```cs +var proposalId = (await acs3DemoContractStub.CreateProposal.SendAsync(new CreateProposalInput +{ + OrganizationAddress = OrganizationAddress + ContractMethodName = nameof(acs3DemoContractStub.SetSlogan), + ToAddress = DAppContractAddress, + ExpiredTime = TimestampHelper.GetUtcNow().AddHours(1), + Params = new StringValue {Value = "AElf"}.ToByteString(), + Token = HashHelper.ComputeFrom("AElf") +})).Output; +``` + +#### Check that Slogan is empty, vote, and release: +```cs +// Check slogan +{ + var slogan = await acs3DemoContractStub.GetSlogan.CallAsync(new Empty()); + slogan.Value.ShouldBeEmpty(); +} +await acs3DemoContractStub.Approve.SendAsync(proposalId); +``` +```cs +await acs3DemoContractStub.Release.SendAsync(proposalId); +// Check slogan +{ + var slogan = await acs3DemoContractStub.GetSlogan.CallAsync(new Empty()); + slogan.Value.ShouldBe("AElf"); +} +``` From cfe3deef2da91e4895b5645faf6d5436a6e785c2 Mon Sep 17 00:00:00 2001 From: vasmohi Date: Mon, 24 Jun 2024 18:40:01 +0530 Subject: [PATCH 08/16] Updated ACS4 - Consensus Standard --- .../ACS4 - Consensus Standard.md | 175 ++++++++++++++++++ 1 file changed, 175 insertions(+) diff --git a/docs/Reference/ACS Introduction/ACS4 - Consensus Standard.md b/docs/Reference/ACS Introduction/ACS4 - Consensus Standard.md index e69de29..806f0d0 100644 --- a/docs/Reference/ACS Introduction/ACS4 - Consensus Standard.md +++ b/docs/Reference/ACS Introduction/ACS4 - Consensus Standard.md @@ -0,0 +1,175 @@ +# ACS4 - Consensus Standard +ACS4 customizes consensus mechanisms. + +## Interface +To customize, implement these five interfaces: + +### Methods +| Method Name | Request Type | Response Type | Description | +|--------------------------------|-------------------------------|-----------------------------|------------------------------------------------------------------------------------------------| +| GetConsensusCommand | google.protobuf.BytesValue | acs4.ConsensusCommand | Generate a consensus command based on contract state and the input public key. | +| GetConsensusExtraData | google.protobuf.BytesValue | google.protobuf.BytesValue | Generate extra data when a block is generated. | +| GenerateConsensusTransactions | google.protobuf.BytesValue | acs4.TransactionList | Generate system transactions when a block is generated. Each block has one consensus transaction. | +| ValidateConsensusBeforeExecution | google.protobuf.BytesValue | acs4.ValidationResult | Verify consensus info in the block header before execution. | +| ValidateConsensusAfterExecution | google.protobuf.BytesValue | acs4.ValidationResult | Verify the state info written to consensus after execution. | + +## Types + +### acs4.ConsensusCommand +| Field | Type | Description | +|-------------------------------|--------------------------|------------------------------------------------------------------| +| limit_milliseconds_of_mining_block | int32 | Time limit for mining the next block. | +| hint | bytes | Diverse context according to the consensus protocol. | +| arranged_mining_time | google.protobuf.Timestamp | The arranged mining time. | +| mining_due_time | google.protobuf.Timestamp | The expiration time for mining. | + +### acs4.TransactionList +| Field | Type | Description | +|--------------|----------------|-----------------------------| +| transactions | aelf.Transaction | Consensus system transactions. | + +### acs4.ValidationResult +| Field | Type | Description | +|--------------|--------|------------------------| +| success | bool | Is successful. | +| message | string | Error message. | +| is_re_trigger| bool | Whether to re-trigger mining. | + +### aelf.Address +| Field | Type | Description | +|-------|-------|-------------| +| value | bytes | | + +### aelf.BinaryMerkleTree +| Field | Type | Description | +|------------|-------|-------------------| +| nodes | Hash | Leaf nodes. | +| root | Hash | Root node hash. | +| leaf_count | int32 | Leaf node count. | + +### aelf.Hash +| Field | Type | Description | +|-------|-------|-------------| +| value | bytes | | + +### aelf.LogEvent +| Field | Type | Description | +|--------------|---------|--------------------------| +| address | Address | Contract address. | +| name | string | Name of the log event. | +| indexed | bytes | Indexed data for bloom. | +| non_indexed | bytes | Non-indexed data. | + +### aelf.MerklePath +| Field | Type | Description | +|--------------------|------------------|---------------------| +| merkle_path_nodes | MerklePathNode | Merkle path nodes. | + +### aelf.MerklePathNode +| Field | Type | Description | +|--------------------|-------|--------------------------| +| hash | Hash | Node hash. | +| is_left_child_node | bool | Is it a left child node? | + +### aelf.SInt32Value +| Field | Type | Description | +|-------|-------|-------------| +| value | sint32 | | + +### aelf.SInt64Value +| Field | Type | Description | +|-------|-------|-------------| +| value | sint64 | | + +### aelf.ScopedStatePath +| Field | Type | Description | +|---------|---------|----------------------------------| +| address | Address | Scope address (contract address) | +| path | StatePath | Path of contract state | + +### aelf.SmartContractRegistration +| Field | Type | Description | +|------------------|-------|-----------------------------------| +| category | sint32| Contract code category (0: C#). | +| code | bytes | Byte array of the contract code. | +| code_hash | Hash | Hash of the contract code. | +| is_system_contract | bool | Is it a system contract? | +| version | int32 | Current contract version. | + +### aelf.StatePath +| Field | Type | Description | +|-------|--------|----------------------| +| parts | string | Partial state path. | + +### aelf.Transaction +| Field | Type | Description | +|-------------------|----------|----------------------------------------------------------------| +| from | Address | Sender's address. | +| to | Address | Contract address being called. | +| ref_block_number | int64 | Referenced block number. | +| ref_block_prefix | bytes | First four bytes of the referenced block hash. | +| method_name | string | Method name in the smart contract. | +| params | bytes | Parameters for the smart contract method. | +| signature | bytes | Signature including sender, target method, parameters, and block reference. | + +### aelf.TransactionExecutingStateSet +| Field | Type | Description | +|---------|------------------------------------|-----------------| +| writes | TransactionExecutingStateSet.WritesEntry | Changed states. | +| reads | TransactionExecutingStateSet.ReadsEntry | Read states. | +| deletes | TransactionExecutingStateSet.DeletesEntry | Deleted states. | + +### aelf.TransactionExecutingStateSet.DeletesEntry +| Field | Type | Description | +|-------|-------|-------------| +| key | string| | +| value | bool | | + +### aelf.TransactionExecutingStateSet.ReadsEntry +| Field | Type | Description | +|-------|-------|-------------| +| key | string| | +| value | bool | | + +### aelf.TransactionExecutingStateSet.WritesEntry +| Field | Type | Description | +|-------|-------|-------------| +| key | string| | +| value | bytes | | + +### aelf.TransactionResult +| Field | Type | Description | +|----------------|-------------------------|---------------------------------------------------------------------------| +| transaction_id | Hash | Transaction ID. | +| status | TransactionResultStatus | Transaction result status. | +| logs | LogEvent | Log events. | +| bloom | bytes | Bloom filter for transaction logs. | +| return_value | bytes | Return value of the transaction execution. | +| block_number | int64 | Block height that packages the transaction. | +| block_hash | Hash | Block hash that packages the transaction. | +| error | string | Failed execution error message. | + +### aelf.TransactionResultStatus +| Name | Number | Description | +|----------------------|--------|-------------------------------------------------------------------| +| NOT_EXISTED | 0 | Transaction result does not exist. | +| PENDING | 1 | Transaction is in the pool waiting to be packaged. | +| FAILED | 2 | Transaction execution failed. | +| MINED | 3 | Transaction executed successfully and packaged into a block. | +| CONFLICT | 4 | Conflicts with other transactions when executed in parallel. | +| PENDING_VALIDATION | 5 | Transaction is waiting for validation. | +| NODE_VALIDATION_FAILED | 6 | Transaction validation failed. | + +## Usage +ACS4 methods correspond to the IConsensusService interface in the AElf.Kernel.Consensus project: + +| ACS4 Method | IConsensusService Method | Methodology | Timing | +|------------------------------------|-----------------------------------|--------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| GetConsensusCommand | Task TriggerConsensusAsync | When TriggerConsensusAsync is called, it will use the node's configured account to call the GetConsensusCommand method to obtain block information (ConsensusCommand) | When the node starts; When the BestChainFoundEventData event is thrown; When consensus data validation fails and needs to be triggered again (IsReTrigger field is true). | +| GetConsensusExtraData | Task GetConsensusExtraDataAsync | When a node produces a block, it generates block header info via IBlockExtraDataService, which calls GetConsensusExtraData in the consensus contract | When a node produces a new block. | +| GenerateConsensusTransactions | Task> GenerateConsensusTransactionsAsync | In the process of generating new blocks, a consensus transaction needs to be generated as one of the system transactions | When a node produces a new block. | +| ValidateConsensusBeforeExecution | Task ValidateConsensusBeforeExecutionAsync | The IBlockValidationProvider interface allows adding a new block validator. The consensus validator, ConsensusValidationProvider, calls ValidateConsensusBeforeExecution | When a node produces a new block. | +| ValidateConsensusAfterExecution | Task ValidateConsensusAfterExecutionAsync | The implementation of ValidateBlockAfterExecuteAsync in ConsensusValidationProvider calls ValidateConsensusAfterExecution in the consensus contract | When a node produces a new block. | + +### Example +Refer to the AEDPoS contract implementation. \ No newline at end of file From 1be3cbc8fc62c1b6361f8d1628f3dfe438317b51 Mon Sep 17 00:00:00 2001 From: vasmohi Date: Mon, 24 Jun 2024 18:50:35 +0530 Subject: [PATCH 09/16] Updated ACS5 - Contract Threshold Standard --- .../ACS5 - Contract Threshold Standard.md | 192 ++++++++++++++++++ 1 file changed, 192 insertions(+) diff --git a/docs/Reference/ACS Introduction/ACS5 - Contract Threshold Standard.md b/docs/Reference/ACS Introduction/ACS5 - Contract Threshold Standard.md index e69de29..40abe0f 100644 --- a/docs/Reference/ACS Introduction/ACS5 - Contract Threshold Standard.md +++ b/docs/Reference/ACS Introduction/ACS5 - Contract Threshold Standard.md @@ -0,0 +1,192 @@ +# ACS5 - Contract Threshold Standard +To raise the threshold for using a contract, consider implementing ACS5. + +## Interface +To limit calling a method in a contract, implement these interfaces: + +### Methods +| Method Name | Request Type | Response Type | Description | +|----------------------------|---------------------------------------|-------------------------------|-----------------------------------| +| SetMethodCallingThreshold | acs5.SetMethodCallingThresholdInput | google.protobuf.Empty | Set the threshold for method calling. | +| GetMethodCallingThreshold | google.protobuf.StringValue | acs5.MethodCallingThreshold | Get the threshold for method calling. | + +### Types + +#### acs5.MethodCallingThreshold +| Field | Type | Description | Label | +|-----------------------|-----------------------------------------|-----------------------------------|------------| +| symbol_to_amount | MethodCallingThreshold.SymbolToAmountEntry | The threshold for method calling, token symbol -> amount. | repeated | +| threshold_check_type | ThresholdCheckType | The type of threshold check. | | + +#### acs5.MethodCallingThreshold.SymbolToAmountEntry +| Field | Type | Description | Label | +|-------|--------|-------------|-------| +| key | string | | | +| value | int64 | | | + +#### acs5.SetMethodCallingThresholdInput +| Field | Type | Description | Label | +|----------------------|---------------------------------------------|-------------|-------| +| method | string | The method name to check. | | +| symbol_to_amount | SetMethodCallingThresholdInput.SymbolToAmountEntry | The threshold for method calling, token symbol -> amount. | repeated | +| threshold_check_type | ThresholdCheckType | The type of threshold check. | | + +#### acs5.SetMethodCallingThresholdInput.SymbolToAmountEntry +| Field | Type | Description | Label | +|-------|--------|-------------|-------| +| key | string | | | +| value | int64 | | | + +#### acs5.ThresholdCheckType +| Name | Number | Description | +|----------|--------|--------------------------------------| +| BALANCE | 0 | Check balance only. | +| ALLOWANCE| 1 | Check balance and allowance at the same time. | + +## Usage +ACS5 works similarly to ACS1, which uses a pre-plugin transaction called `ChargeTransactionFees` to charge a transaction fee. ACS5 uses a pre-plugin transaction called `CheckThreshold` to ensure the account sending the transaction can invoke the method. + +### Implementation of `CheckThreshold`: + +```cs +public override Empty CheckThreshold(CheckThresholdInput input) +{ + var meetThreshold = false; + var meetBalanceSymbolList = new List(); + foreach (var symbolToThreshold in input.SymbolToThreshold) + { + if (GetBalance(input.Sender, symbolToThreshold.Key) < symbolToThreshold.Value) + continue; + meetBalanceSymbolList.Add(symbolToThreshold.Key); + } + if (meetBalanceSymbolList.Count > 0) + { + if (input.IsCheckAllowance) + { + foreach (var symbol in meetBalanceSymbolList) + { + if (State.Allowances[input.Sender][Context.Sender][symbol] < + input.SymbolToThreshold[symbol]) continue; + meetThreshold = true; + break; + } + } + else + { + meetThreshold = true; + } + } + if (input.SymbolToThreshold.Count == 0) + { + meetThreshold = true; + } + Assert(meetThreshold, "Cannot meet the calling threshold."); + return new Empty(); +} +``` + +If the sender's token balance or the authorized amount for the target contract doesn't meet the set limit, the pre-plugin transaction throws an exception and prevents the original transaction from executing. + +## Implementation +Implement a single `GetMethodCallingThreshold` method like `GetMethodFee` in ACS1. Use `MappedState` in the State class: +```cs +public MappedState MethodCallingThresholds { get; set; } +``` + +Configure the call permission of SetMethodCallingThreshold, requiring an Admin in the State: +```cs +public SingletonState
Admin { get; set; } +``` +```cs +public override Empty SetMethodCallingThreshold(SetMethodCallingThresholdInput input) +{ + Assert(State.Admin.Value == Context.Sender, "No permission."); + State.MethodCallingThresholds[input.Method] = new MethodCallingThreshold + { + SymbolToAmount = {input.SymbolToAmount} + }; + return new Empty(); +} + +public override MethodCallingThreshold GetMethodCallingThreshold(StringValue input) +{ + return State.MethodCallingThresholds[input.Value]; +} + +public override Empty Foo(Empty input) +{ + return new Empty(); +} + +message SetMethodCallingThresholdInput { + string method = 1; + map symbol_to_amount = 2;// The order matters. + ThresholdCheckType threshold_check_type = 3; +} +``` + +## Test +Test the Foo method: + +1. Make a Stub +```cs +var keyPair = SampleECKeyPairs.KeyPairs[0]; +var acs5DemoContractStub = + GetTester(DAppContractAddress, keyPair); +``` + +2. Check the current threshold (should be 0): +```cs +var methodResult = await acs5DemoContractStub.GetMethodCallingThreshold.CallAsync( + new StringValue + { + Value = nameof(acs5DemoContractStub.Foo) + }); +methodResult.SymbolToAmount.Count.ShouldBe(0); +``` + +3. Ensure the caller's ELF balance is greater than 1 ELF: +```cs +await acs5DemoContractStub.SetMethodCallingThreshold.SendAsync( + new SetMethodCallingThresholdInput + { + Method = nameof(acs5DemoContractStub.Foo), + SymbolToAmount = + { + {"ELF", 1_0000_0000} + }, + ThresholdCheckType = ThresholdCheckType.Balance + }); +``` + +4. Check the threshold again: +```cs +methodResult = await acs5DemoContractStub.GetMethodCallingThreshold.CallAsync( + new StringValue + { + Value = nameof(acs5DemoContractStub.Foo) + }); +methodResult.SymbolToAmount.Count.ShouldBe(1); +methodResult.ThresholdCheckType.ShouldBe(ThresholdCheckType.Balance); +``` + +5. Send the Foo transaction with an account that has enough balance: +```cs +// Call with enough balance. +{ + var executionResult = await acs5DemoContractStub.Foo.SendAsync(new Empty()); + executionResult.TransactionResult.Status.ShouldBe(TransactionResultStatus.Mined); +} +``` + +6. Send the Foo transaction with an account without ELF: +```cs +// Call without enough balance. +{ + var poorStub = + GetTester(DAppContractAddress, + SampleECKeyPairs.KeyPairs[1]); + var executionResult = await poorStub.Foo.SendWithExceptionAsync(new Empty()); + executionResult.TransactionResult.Error.ShouldContain("Cannot meet the calling threshold."); +} +``` From 9238b545fae09bbbe3801391e57456dd9ecb3ea5 Mon Sep 17 00:00:00 2001 From: vasmohi Date: Mon, 24 Jun 2024 18:53:13 +0530 Subject: [PATCH 10/16] Updated ACS6 - Random Number Generation --- .../ACS6 - Random Number Generation.md | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/docs/Reference/ACS Introduction/ACS6 - Random Number Generation.md b/docs/Reference/ACS Introduction/ACS6 - Random Number Generation.md index e69de29..54d7f4b 100644 --- a/docs/Reference/ACS Introduction/ACS6 - Random Number Generation.md +++ b/docs/Reference/ACS Introduction/ACS6 - Random Number Generation.md @@ -0,0 +1,34 @@ +# ACS6 - Random Number Provider Standard +To generate a random number in your contract, use ACS6. + +## Interface +To provide a random number based on input, implement this interface: + +### Methods +| Method Name | Request Type | Response Type | Description | +|-----------------|----------------------------|----------------------------|-------------------------------------------| +| GetRandomBytes | google.protobuf.BytesValue | google.protobuf.BytesValue | Get the random number provided by the contract. | + +## Usage +Override the `GetRandomBytes` method to return a random number based on the given input. The logic for generating the random number is up to you. Ensure you return a `BytesValue` type so the caller can deserialize the output. + +## Implementation +The simplest implementation: + +```cs +public override BytesValue GetRandomBytes(BytesValue input) +{ + var serializedInput = new GetRandomBytesInput(); + serializedInput.MergeFrom(input.Value); + var value = new Hash(); + value.MergeFrom(serializedInput.Value); + var randomHashFromContext = Context.GetRandomHash(value); + + return new BytesValue + { + Value = serializedInput.Kind == 1 + ? new BytesValue {Value = randomHashFromContext.Value}.ToByteString() + : new Int64Value {Value = Context.ConvertHashToInt64(randomHashFromContext, 1, 10000)}.ToByteString() + }; +} +``` \ No newline at end of file From 0015b15cacd02c72b5596d7774e31f8ee64b6017 Mon Sep 17 00:00:00 2001 From: vasmohi Date: Mon, 24 Jun 2024 19:03:52 +0530 Subject: [PATCH 11/16] Updated ACS7 - Cross Chain Standard --- .../ACS7 - Cross Chain Standard.md | 95 +++++++++++++++++++ 1 file changed, 95 insertions(+) diff --git a/docs/Reference/ACS Introduction/ACS7 - Cross Chain Standard.md b/docs/Reference/ACS Introduction/ACS7 - Cross Chain Standard.md index e69de29..03f669f 100644 --- a/docs/Reference/ACS Introduction/ACS7 - Cross Chain Standard.md +++ b/docs/Reference/ACS Introduction/ACS7 - Cross Chain Standard.md @@ -0,0 +1,95 @@ +# ACS7 - Contract CrossChain Standard + +ACS7 is for implementing cross-chain contracts. + +## Interface + +This involves methods for chain creation and indexing: + +### Methods + +| Method Name | Request Type | Response Type | Description | +|-------------------------------------|---------------------------------------------|--------------------------------|---------------------------------------------------------------------| +| ProposeCrossChainIndexing | acs7.CrossChainBlockData | google.protobuf.Empty | Propose a cross-chain indexing. | +| ReleaseCrossChainIndexingProposal | acs7.ReleaseCrossChainIndexingProposalInput | google.protobuf.Empty | Release the proposed indexing if approved. | +| RequestSideChainCreation | acs7.SideChainCreationRequest | google.protobuf.Empty | Request side chain creation. | +| ReleaseSideChainCreation | acs7.ReleaseSideChainCreationInput | google.protobuf.Empty | Release the side chain creation request if approved. | +| CreateSideChain | acs7.CreateSideChainInput | google.protobuf.Int32Value | Create the side chain and return its ID. Only authorized users. | +| Recharge | acs7.RechargeInput | google.protobuf.Empty | Recharge a specified side chain. | +| DisposeSideChain | google.protobuf.Int32Value | google.protobuf.Int32Value | Dispose a side chain by ID. Only authorized users. | +| AdjustIndexingFeePrice | acs7.AdjustIndexingFeeInput | google.protobuf.Empty | Adjust side chain indexing fee. Only authorized users. | +| VerifyTransaction | acs7.VerifyTransactionInput | google.protobuf.BoolValue | Verify a cross-chain transaction. | +| GetSideChainIdAndHeight | google.protobuf.Empty | acs7.ChainIdAndHeightDict | Get all side chain IDs and heights. | +| GetSideChainIndexingInformationList | google.protobuf.Empty | acs7.SideChainIndexingInformationList | Get indexing information of side chains. | +| GetAllChainsIdAndHeight | google.protobuf.Empty | acs7.ChainIdAndHeightDict | Get IDs and heights of all chains. | +| GetIndexedSideChainBlockDataByHeight| google.protobuf.Int64Value | acs7.IndexedSideChainBlockData | Get block data of indexed side chain by height. | +| GetBoundParentChainHeightAndMerklePathByHeight | google.protobuf.Int64Value | acs7.CrossChainMerkleProofContext | Get Merkle path bound to side chain by height. | +| GetChainInitializationData | google.protobuf.Int32Value | acs7.ChainInitializationData | Get initialization data for a specified side chain. | + +### Types + +#### acs7.AdjustIndexingFeeInput +| Field | Description | Label | +|--------------------|-------------------------|----------| +| `side_chain_id` (int32) | The side chain ID | | +| `indexing_fee` (int64) | The new indexing fee | | + +#### acs7.ChainIdAndHeightDict +| Field | Description | Label | +|--------------------------|-------------------------|-----------| +| `id_height_dict` (map) | Chain IDs and heights | repeated | + +#### acs7.ChainInitializationData +| Field | Description | Label | +|----------------------------------------|------------------------------------|---------| +| `chain_id` (int32) | Side chain ID | | +| `creator` (aelf.Address) | Creator's address | | +| `creation_timestamp` (google.protobuf.Timestamp) | Creation timestamp | | +| `creation_height_on_parent_chain` (int64) | Height on parent chain | | +| `chain_creator_privilege_preserved` (bool) | If privilege is preserved | | +| `parent_chain_token_contract_address` (aelf.Address) | Token contract address | | +| `chain_initialization_consensus_info` (ChainInitializationConsensusInfo) | Initial consensus info | | +| `native_token_info_data` (bytes) | Native token info | | +| `resource_token_info` (ResourceTokenInfo) | Resource token info | | +| `chain_primary_token_info` (ChainPrimaryTokenInfo) | Primary token info | | + +#### acs7.CreateSideChainInput +| Field | Description | Label | +|------------------------------------|---------------------------------|----------| +| `side_chain_creation_request` (SideChainCreationRequest) | Creation request info | | +| `proposer` (aelf.Address) | Proposer's address | | + +#### acs7.CrossChainBlockData +| Field | Description | Label | +|-------------------------------------|---------------------------------|-----------| +| `side_chain_block_data_list` (repeated SideChainBlockData) | List of side chain block data | repeated | +| `parent_chain_block_data_list` (repeated ParentChainBlockData) | List of parent chain block data | repeated | + +#### acs7.RechargeInput +| Field | Description | Label | +|--------------------|-------------------------|----------| +| `chain_id` (int32) | Side chain ID | | +| `amount` (int64) | Amount to recharge | | + +#### acs7.ReleaseCrossChainIndexingProposalInput +| Field | Description | Label | +|----------------------------|-----------------------------|-----------| +| `chain_id_list` (repeated int32) | List of chain IDs to release | repeated | + +#### acs7.ReleaseSideChainCreationInput +| Field | Description | Label | +|--------------------|-------------------------|----------| +| `proposal_id` (aelf.Hash) | Proposal ID | | + +#### acs7.SideChainCreationRequest +| Field | Description | Label | +|------------------------------------------|------------------------------------|-----------| +| `indexing_price` (int64) | Cross-chain indexing price | | +| `locked_token_amount` (int64) | Initial locked balance | | +| `is_privilege_preserved` (bool) | If privilege is preserved | | +| `side_chain_token_creation_request` (SideChainTokenCreationRequest) | Token creation request | | +| `side_chain_token_initial_issue_list` (repeated SideChainTokenInitialIssue) | Initial token issues list | repeated | +| `initial_resource_amount` (repeated SideChainCreationRequest.InitialResourceAmountEntry) | Initial resource amounts | repeated | + +### Example +ACS7 defines methods for cross-chain scenarios. AElf provides an implementation for ACS7 called `CrossChainContract`. Refer to this implementation for more details. \ No newline at end of file From 76e9bd1330c54fd5145fad0cdd45281ffa58e70b Mon Sep 17 00:00:00 2001 From: vasmohi Date: Mon, 24 Jun 2024 19:09:24 +0530 Subject: [PATCH 12/16] Updated ACS8 - Transaction Resource Token Fee Standard --- ...Transaction Resource Token Fee Standard.md | 74 +++++++++++++++++++ 1 file changed, 74 insertions(+) diff --git a/docs/Reference/ACS Introduction/ACS8 - Transaction Resource Token Fee Standard.md b/docs/Reference/ACS Introduction/ACS8 - Transaction Resource Token Fee Standard.md index e69de29..ff99d54 100644 --- a/docs/Reference/ACS Introduction/ACS8 - Transaction Resource Token Fee Standard.md +++ b/docs/Reference/ACS Introduction/ACS8 - Transaction Resource Token Fee Standard.md @@ -0,0 +1,74 @@ +# ACS8 - Transaction Resource Token Fee Standard +ACS8 is a transaction fee standard similar to ACS1, but it charges the called contract rather than the user. The fee charged includes four specified tokens: WRITE, READ, NET, and TRAFFIC. + +When a contract inherits from ACS8, each transaction within this contract incurs charges in these four resource tokens. + +## Interface +The acs8.proto file defines the following method: + +### Methods +| Method Name | Request Type | Response Type | Description | +|-------------------|-----------------------------|-------------------|--------------------------------------------------| +| BuyResourceToken | acs8.BuyResourceTokenInput | google.protobuf.Empty | Buys one of the four resource tokens. Consumes ELF balance in the contract account. | + +### Types + +#### acs8.BuyResourceTokenInput +| Field | Type | Description | Label | +|------------|--------|-----------------------------------------------|-----------| +| symbol | string | The symbol of the token to buy. | | +| amount | int64 | The amount of token to buy. | | +| pay_limit | int64 | Limit of cost; buying is abandoned if exceeded. 0 means no limit. | | + +## Usage +Contracts inheriting ACS1 use a pre-plugin transaction called ChargeTransactionFees for transaction fee charging. ACS8 introduces a similar post-plugin transaction called ChargeResourceToken, which charges resource tokens based on actual transaction consumption. + +The ChargeResourceToken implementation involves calculating token amounts using polynomial coefficients stored in CalculateFeeCoefficients defined in token_contract.proto. Each resource token has a polynomial for fee calculation, which determines the cost based on transaction consumption. +```cs +public override Empty ChargeResourceToken(ChargeResourceTokenInput input) +{ + Context.LogDebug(() => string.Format("Start executing ChargeResourceToken.{0}", input)); + if (input.Equals(new ChargeResourceTokenInput())) + { + return new Empty(); + } + var bill = new TransactionFeeBill(); + foreach (var pair in input.CostDic) + { + Context.LogDebug(() => string.Format("Charging {0} {1} tokens.", pair.Value, pair.Key)); + var existingBalance = GetBalance(Context.Sender, pair.Key); + Assert(existingBalance >= pair.Value, + string.Format("Insufficient resource of {0}. Need balance: {1}; Current balance: {2}.", pair.Key, pair.Value, existingBalance)); + bill.FeesMap.Add(pair.Key, pair.Value); + } + foreach (var pair in bill.FeesMap) + { + Context.Fire(new ResourceTokenCharged + { + Symbol = pair.Key, + Amount = pair.Value, + ContractAddress = Context.Sender + }); + if (pair.Value == 0) + { + Context.LogDebug(() => string.Format("Maybe incorrect charged resource fee of {0}: it's 0.", pair.Key)); + } + } + return new Empty(); +} +``` + +Additionally, contracts cannot execute methods if they lack sufficient resource token balance. To enforce this, a pre-plugin transaction CheckResourceToken, similar to ACS5, verifies the contract's resource token balance before method execution. +```cs +public override Empty CheckResourceToken(Empty input) +{ + foreach (var symbol in Context.Variables.GetStringArray(TokenContractConstants.PayTxFeeSymbolListName)) + { + var balance = GetBalance(Context.Sender, symbol); + var owningBalance = State.OwningResourceToken[Context.Sender][symbol]; + Assert(balance > owningBalance, + string.Format("Contract balance of {0} token is not enough. Owning {1}.", symbol, owningBalance)); + } + return new Empty(); +} +``` \ No newline at end of file From 96a920becb5b226490878b0d52edf6e672dee69b Mon Sep 17 00:00:00 2001 From: vasmohi Date: Mon, 24 Jun 2024 19:25:23 +0530 Subject: [PATCH 13/16] Updated ACS9 - Contract profit Dividend Standard --- ...CS9 - Contract Profit Dividend Standard.md | 483 ++++++++++++++++++ 1 file changed, 483 insertions(+) diff --git a/docs/Reference/ACS Introduction/ACS9 - Contract Profit Dividend Standard.md b/docs/Reference/ACS Introduction/ACS9 - Contract Profit Dividend Standard.md index e69de29..08293b0 100644 --- a/docs/Reference/ACS Introduction/ACS9 - Contract Profit Dividend Standard.md +++ b/docs/Reference/ACS Introduction/ACS9 - Contract Profit Dividend Standard.md @@ -0,0 +1,483 @@ +# ACS9 - Contract Profit Dividend Standard +ACS9 defines a standard for distributing profits on AElf's side chain contracts. + +## Interface +ACS9 includes several methods given below: + +### Methods +| Method Name | Request Type | Response Type | Description | +|----------------------|-------------------------------|----------------------------|---------------------------------------------| +| TakeContractProfits | acs9.TakeContractProfitsInput | google.protobuf.Empty | Allows developers to collect contract profits. | +| GetProfitConfig | google.protobuf.Empty | acs9.ProfitConfig | Retrieves profit distribution configuration. | +| GetProfitsAmount | google.protobuf.Empty | acs9.ProfitsMap | Queries total profits accumulated by the contract. | + +### Types + +#### acs9.ProfitConfig +| Field | Type | Description | Label | +|--------------------------------|----------|-----------------------------------------------|------------| +| donation_parts_per_hundred | int32 | Percentage of profit donated to dividend pool. | | +| profits_token_symbol_list | string | List of profit token symbols. | repeated | +| staking_token_symbol | string | Token symbol users can lock to claim profits. | | + +#### acs9.ProfitsMap +| Field | Type | Description | Label | +|---------------|------------------------------------|------------------------------------------|-----------| +| value | map | Profits accumulated, symbol -> amount. | repeated | + +#### acs9.TakeContractProfitsInput +| Field | Type | Description | Label | +|---------------|--------|-----------------------------------|-----------| +| symbol | string | Token symbol to withdraw profits. | | +| amount | int64 | Amount of token to withdraw. | | + +## Implementation +The contract initializes by creating a token called APP and establishing a profit distribution scheme using the TokenHolder contract. Users receive 10 APP tokens upon signing up and can deposit ELF to receive APP tokens. The Use method consumes APP tokens. + +Upon initialization, ACS9 sets the profit configuration and enables profit distribution to the profit receiver and dividend pool. + +The contract allows users to interact by signing up, depositing and withdrawing tokens, and using APP tokens for transactions. Developers can configure profit distribution settings and monitor accumulated profits. + +1. Implementation of Initialize +```cs +public override Empty Initialize(InitializeInput input) +{ + State.TokenHolderContract.Value = + Context.GetContractAddressByName(SmartContractConstants.TokenHolderContractSystemName); + State.TokenContract.Value = + Context.GetContractAddressByName(SmartContractConstants.TokenContractSystemName); + State.DividendPoolContract.Value = + Context.GetContractAddressByName(input.DividendPoolContractName.Value.ToBase64()); + State.Symbol.Value = input.Symbol == string.Empty ? "APP" : input.Symbol; + State.ProfitReceiver.Value = input.ProfitReceiver; + CreateToken(input.ProfitReceiver); + // To test TokenHolder Contract. + CreateTokenHolderProfitScheme(); + // To test ACS9 workflow. + SetProfitConfig(); + State.ProfitReceiver.Value = input.ProfitReceiver; + return new Empty(); +} +private void CreateToken(Address profitReceiver, bool isLockWhiteListIncludingSelf = false) +{ + var lockWhiteList = new List
+ {Context.GetContractAddressByName(SmartContractConstants.TokenHolderContractSystemName)}; + if (isLockWhiteListIncludingSelf) + lockWhiteList.Add(Context.Self); + State.TokenContract.Create.Send(new CreateInput + { + Symbol = State.Symbol.Value, + TokenName = "DApp Token", + Decimals = ACS9DemoContractConstants.Decimal, + Issuer = Context.Self, + IsBurnable = true, + IsProfitable = true, + TotalSupply = ACS9DemoContractConstants.TotalSupply, + LockWhiteList = + { + lockWhiteList + } + }); + State.TokenContract.Issue.Send(new IssueInput + { + To = profitReceiver, + Amount = ACS9DemoContractConstants.TotalSupply / 5, + Symbol = State.Symbol.Value, + Memo = "Issue token for profit receiver" + }); +} +private void CreateTokenHolderProfitScheme() +{ + State.TokenHolderContract.CreateScheme.Send(new CreateTokenHolderProfitSchemeInput + { + Symbol = State.Symbol.Value + }); +} +private void SetProfitConfig() +{ + State.ProfitConfig.Value = new ProfitConfig + { + DonationPartsPerHundred = 1, + StakingTokenSymbol = "APP", + ProfitsTokenSymbolList = {"ELF"} + }; +} +``` + +2. The user can use the SighUp method to register and get the bonus +```cs +/// +/// When user sign up, give him 10 APP tokens, then initialize his profile. +/// +/// +/// +public override Empty SignUp(Empty input) +{ + Assert(State.Profiles[Context.Sender] == null, "Already registered."); + var profile = new Profile + { + UserAddress = Context.Sender + }; + State.TokenContract.Issue.Send(new IssueInput + { + Symbol = State.Symbol.Value, + Amount = ACS9DemoContractConstants.ForNewUser, + To = Context.Sender + }); + // Update profile. + profile.Records.Add(new Record + { + Type = RecordType.SignUp, + Timestamp = Context.CurrentBlockTime, + Description = string.Format("{0} +{1}",State.Symbol.Value, ACS9DemoContractConstants.ForNewUser) + }); + State.Profiles[Context.Sender] = profile; + return new Empty(); +} +``` + +3. Recharge and redemption: +```cs +public override Empty Deposit(DepositInput input) +{ + // User Address -> DApp Contract. + State.TokenContract.TransferFrom.Send(new TransferFromInput + { + From = Context.Sender, + To = Context.Self, + Symbol = "ELF", + Amount = input.Amount + }); + State.TokenContract.Issue.Send(new IssueInput + { + Symbol = State.Symbol.Value, + Amount = input.Amount, + To = Context.Sender + }); + // Update profile. + var profile = State.Profiles[Context.Sender]; + profile.Records.Add(new Record + { + Type = RecordType.Deposit, + Timestamp = Context.CurrentBlockTime, + Description = string.Format("{0} +{1}", State.Symbol.Value, input.Amount) + }); + State.Profiles[Context.Sender] = profile; + return new Empty(); +} +public override Empty Withdraw(WithdrawInput input) +{ + State.TokenContract.TransferFrom.Send(new TransferFromInput + { + From = Context.Sender, + To = Context.Self, + Symbol = State.Symbol.Value, + Amount = input.Amount + }); + State.TokenContract.Transfer.Send(new TransferInput + { + To = Context.Sender, + Symbol = input.Symbol, + Amount = input.Amount + }); + State.TokenHolderContract.RemoveBeneficiary.Send(new RemoveTokenHolderBeneficiaryInput + { + Beneficiary = Context.Sender, + Amount = input.Amount + }); + // Update profile. + var profile = State.Profiles[Context.Sender]; + profile.Records.Add(new Record + { + Type = RecordType.Withdraw, + Timestamp = Context.CurrentBlockTime, + Description = string.Format("{0} -{1}", State.Symbol.Value, input.Amount) + }); + State.Profiles[Context.Sender] = profile; + return new Empty(); +} +``` + +4. Implementation of Use directly transfers 1/3 profits into the token holder dividend scheme: +```cs +public override Empty Use(Record input) +{ + State.TokenContract.TransferFrom.Send(new TransferFromInput + { + From = Context.Sender, + To = Context.Self, + Symbol = State.Symbol.Value, + Amount = ACS9DemoContractConstants.UseFee + }); + if (input.Symbol == string.Empty) + input.Symbol = State.TokenContract.GetPrimaryTokenSymbol.Call(new Empty()).Value; + var contributeAmount = ACS9DemoContractConstants.UseFee.Div(3); + State.TokenContract.Approve.Send(new ApproveInput + { + Spender = State.TokenHolderContract.Value, + Symbol = input.Symbol, + Amount = contributeAmount + }); + // Contribute 1/3 profits (ELF) to profit scheme. + State.TokenHolderContract.ContributeProfits.Send(new ContributeProfitsInput + { + SchemeManager = Context.Self, + Amount = contributeAmount, + Symbol = input.Symbol + }); + // Update profile. + var profile = State.Profiles[Context.Sender]; + profile.Records.Add(new Record + { + Type = RecordType.Withdraw, + Timestamp = Context.CurrentBlockTime, + Description = string.Format("{0} -{1}", State.Symbol.Value, ACS9DemoContractConstants.UseFee), + Symbol = input.Symbol + }); + State.Profiles[Context.Sender] = profile; + return new Empty(); +} +``` +5. Implement ACS9 for the perfect profit distribution: +```cs +public override Empty TakeContractProfits(TakeContractProfitsInput input) +{ + var config = State.ProfitConfig.Value; + // For Side Chain Dividends Pool. + var amountForSideChainDividendsPool = input.Amount.Mul(config.DonationPartsPerHundred).Div(100); + State.TokenContract.Approve.Send(new ApproveInput + { + Symbol = input.Symbol, + Amount = amountForSideChainDividendsPool, + Spender = State.DividendPoolContract.Value + }); + State.DividendPoolContract.Donate.Send(new DonateInput + { + Symbol = input.Symbol, + Amount = amountForSideChainDividendsPool + }); + // For receiver. + var amountForReceiver = input.Amount.Sub(amountForSideChainDividendsPool); + State.TokenContract.Transfer.Send(new TransferInput + { + To = State.ProfitReceiver.Value, + Amount = amountForReceiver, + Symbol = input.Symbol + }); + // For Token Holder Profit Scheme. (To distribute.) + State.TokenHolderContract.DistributeProfits.Send(new DistributeProfitsInput + { + SchemeManager = Context.Self + }); + return new Empty(); +} +public override ProfitConfig GetProfitConfig(Empty input) +{ + return State.ProfitConfig.Value; +} +public override ProfitsMap GetProfitsAmount(Empty input) +{ + var profitsMap = new ProfitsMap(); + foreach (var symbol in State.ProfitConfig.Value.ProfitsTokenSymbolList) + { + var balance = State.TokenContract.GetBalance.Call(new GetBalanceInput + { + Owner = Context.Self, + Symbol = symbol + }).Balance; + profitsMap.Value[symbol] = balance; + } + return profitsMap; +} +``` + +## Test + +Testing involves deploying contracts implementing ACS9 or ACS10, initializing the ACS9 contract using IContractInitializationProvider, and verifying profit distribution among stakeholders. + +- Before the testing begins, the contract implementing ACS9 can be initialized by interface IContractInitializationProvider +```cs +public class ACS9DemoContractInitializationProvider : IContractInitializationProvider +{ + public List GetInitializeMethodList(byte[] contractCode) + { + return new List + { + new InitializeMethod + { + MethodName = nameof(ACS9DemoContract.Initialize), + Params = new InitializeInput + { + ProfitReceiver = Address.FromPublicKey(SampleECKeyPairs.KeyPairs.Skip(3).First().PublicKey), + DividendPoolContractName = ACS10DemoSmartContractNameProvider.Name + }.ToByteString() + } + }; + } + public Hash SystemSmartContractName { get; } = ACS9DemoSmartContractNameProvider.Name; + public string ContractCodeName { get; } = "AElf.Contracts.ACS9DemoContract"; +} +``` + +- Prepare a user account: +```cs +protected List UserKeyPairs => SampleECKeyPairs.KeyPairs.Skip(2).Take(3).ToList(); +``` + +- Prepare some Stubs: +```cs +var keyPair = UserKeyPairs[0]; +var address = Address.FromPublicKey(keyPair.PublicKey); +// Prepare stubs. +var acs9DemoContractStub = GetACS9DemoContractStub(keyPair); +var acs10DemoContractStub = GetACS10DemoContractStub(keyPair); +var userTokenStub = + GetTester(TokenContractAddress, UserKeyPairs[0]); +var userTokenHolderStub = + GetTester(TokenHolderContractAddress, + UserKeyPairs[0]); +``` + +- Then, transfer ELF to the user (TokenContractStub is the Stub of the initial bp who has much ELF) : +```cs +// Transfer some ELFs to user. +await TokenContractStub.Transfer.SendAsync(new TransferInput +{ + To = address, + Symbol = "ELF", + Amount = 1000_00000000 +}); +``` + +- User have to call SignUp to check if they got 10 APP tokens: +```cs +await acs9DemoContractStub.SignUp.SendAsync(new Empty()); +// User has 10 APP tokens because of signing up. +(await GetFirstUserBalance("APP")).ShouldBe(10_00000000); +``` + +- Test the recharge method of the contract itself: +```cs +var elfBalanceBefore = await GetFirstUserBalance("ELF"); +// User has to Approve an amount of ELF tokens before deposit to the DApp. +await userTokenStub.Approve.SendAsync(new ApproveInput +{ + Amount = 1000_00000000, + Spender = ACS9DemoContractAddress, + Symbol = "ELF" +}); +await acs9DemoContractStub.Deposit.SendAsync(new DepositInput +{ + Amount = 100_00000000 +}); +// Check the change of balance of ELF. +var elfBalanceAfter = await GetFirstUserBalance("ELF"); +elfBalanceAfter.ShouldBe(elfBalanceBefore - 100_00000000); +// Now user has 110 APP tokens. +(await GetFirstUserBalance("APP")).ShouldBe(110_00000000); +``` + +- The user locks up 57 APP via the TokenHolder contract in order to obtain profits from the contract: +```cs +// User lock some APP tokens for getting profits. (APP -57) +await userTokenHolderStub.RegisterForProfits.SendAsync(new RegisterForProfitsInput +{ + SchemeManager = ACS9DemoContractAddress, + Amount = 57_00000000 +}); +``` + +- The Use method is invoked 10 times and 0.3 APP is consumed each time, and finally the user have 50 APP left: +```cs +await userTokenStub.Approve.SendAsync(new ApproveInput +{ + Amount = long.MaxValue, + Spender = ACS9DemoContractAddress, + Symbol = "APP" +}); +// User uses 10 times of this DApp. (APP -3) +for (var i = 0; i < 10; i++) +{ + await acs9DemoContractStub.Use.SendAsync(new Record()); +} +// Now user has 50 APP tokens. +(await GetFirstUserBalance("APP")).ShouldBe(50_00000000); +``` + +- Using the TakeContractProfits method, the developer attempts to withdraw 10 ELF as profits. The 10 ELF will be transferred to the developer in this method: +```cs +const long baseBalance = 0; +{ + var balance = await TokenContractStub.GetBalance.CallAsync(new GetBalanceInput + { + Owner = UserAddresses[1], Symbol = "ELF" + }); + balance.Balance.ShouldBe(baseBalance); +} +// Profits receiver claim 10 ELF profits. +await acs9DemoContractStub.TakeContractProfits.SendAsync(new TakeContractProfitsInput +{ + Symbol = "ELF", + Amount = 10_0000_0000 +}); +// Then profits receiver should have 9.9 ELF tokens. +{ + var balance = await TokenContractStub.GetBalance.CallAsync(new GetBalanceInput + { + Owner = UserAddresses[1], Symbol = "ELF" + }); + balance.Balance.ShouldBe(baseBalance + 9_9000_0000); +} +``` + +- Next check the profit distribution results. The dividend pool should be allocated 0.1 ELF: +```cs +// And Side Chain Dividends Pool should have 0.1 ELF tokens. +{ + var scheme = await TokenHolderContractStub.GetScheme.CallAsync(ACS10DemoContractAddress); + var virtualAddress = await ProfitContractStub.GetSchemeAddress.CallAsync(new SchemePeriod + { + SchemeId = scheme.SchemeId, + Period = 0 + }); + var balance = await TokenContractStub.GetBalance.CallAsync(new GetBalanceInput + { + Owner = virtualAddress, + Symbol = "ELF" + }); + balance.Balance.ShouldBe(1000_0000); +} +``` + +- The user receives 1 ELF from the token holder dividend scheme: +```cs +// Help user to claim profits from token holder profit scheme. +await TokenHolderContractStub.ClaimProfits.SendAsync(new ClaimProfitsInput +{ + Beneficiary = UserAddresses[0], + SchemeManager = ACS9DemoContractAddress, +}); +// Profits should be 1 ELF. +(await GetFirstUserBalance("ELF")).ShouldBe(elfBalanceAfter + 1_0000_0000); +``` + +- Finally, let’s test the Withdraw method. +```cs +// Withdraw +var beforeBalance = + await userTokenStub.GetBalance.CallAsync(new GetBalanceInput + { + Symbol = "APP", + Owner = UserAddresses[0] + }); +var withDrawResult = await userTokenHolderStub.Withdraw.SendAsync(ACS9DemoContractAddress); +withDrawResult.TransactionResult.Status.ShouldBe(TransactionResultStatus.Mined); +var resultBalance = await userTokenStub.GetBalance.CallAsync(new GetBalanceInput +{ + Symbol = "APP", + Owner = UserAddresses[0] +}); +resultBalance.Balance.ShouldBe(beforeBalance.Balance + 57_00000000); +``` + +This documentation provides a framework for implementing profit distribution and verifying its functionality through various test scenarios. \ No newline at end of file From 822c9c010589e1d36e0ed4e7b92d34adad10b1ae Mon Sep 17 00:00:00 2001 From: vasmohi Date: Mon, 24 Jun 2024 19:54:45 +0530 Subject: [PATCH 14/16] Updated ACS10 - Divident Pool Standard --- .../ACS10 - Dividend Pool Standard.md | 421 ++++++++++++++++++ 1 file changed, 421 insertions(+) diff --git a/docs/Reference/ACS Introduction/ACS10 - Dividend Pool Standard.md b/docs/Reference/ACS Introduction/ACS10 - Dividend Pool Standard.md index e69de29..a09b12d 100644 --- a/docs/Reference/ACS Introduction/ACS10 - Dividend Pool Standard.md +++ b/docs/Reference/ACS Introduction/ACS10 - Dividend Pool Standard.md @@ -0,0 +1,421 @@ +# ACS10 - Dividend Pool Standard +ACS10 facilitates the creation and management of dividend pools within a contract. + +## Interface +To create a dividend pool, implement these optional interfaces: + +### Methods +| Method Name | Request Type | Response Type | Description | +|--------------------------|-----------------------|-------------------------|---------------------------------------------------------------------------------------------------| +| Donate | `acs10.DonateInput` | `google.protobuf.Empty` | Transfers tokens from the caller to the dividend pool. Converts non-native tokens to native tokens if required. | +| Release | `acs10.ReleaseInput` | `google.protobuf.Empty` | Releases dividends based on the specified period number. | +| SetSymbolList | `acs10.SymbolList` | `google.protobuf.Empty` | Sets the list of token symbols supported by the dividend pool. | +| GetSymbolList | `google.protobuf.Empty` | `acs10.SymbolList` | Retrieves the list of token symbols supported by the dividend pool. | +| GetUndistributedDividends| `google.protobuf.Empty` | `acs10.Dividends` | Queries the balance of undistributed tokens according to the symbol list. | +| GetDividends | `google.protobuf.Int64Value` | `acs10.Dividends` | Queries dividend information based on the specified height. | + + +### Types + +#### `acs10.Dividends` +| Field | Type | Description | Label | +|--------|--------------------|----------------------------------------|--------| +| `value`| `Dividends.ValueEntry` | The dividends, symbol -> amount. | repeated | + +#### `acs10.Dividends.ValueEntry` +| Field | Type | Description | Label | +|--------|----------|---------------|-------| +| `key` | `string` | | | +| `value`| `int64` | | | + +#### `acs10.DonateInput` +| Field | Type | Description | Label | +|----------|----------|-----------------------------|-------| +| `symbol` | `string` | The token symbol to donate. | | +| `amount` | `int64` | The amount to donate. | | + +#### `acs10.DonationReceived` +| Field | Type | Description | Label | +|-----------------|-----------------|-------------------------------|--------| +| `from` | `aelf.Address` | The address of donors. | | +| `pool_contract` | `aelf.Address` | The address of dividend pool. | | +| `symbol` | `string` | The token symbol Donated. | | +| `amount` | `int64` | The amount Donated. | | + +#### `acs10.ReleaseInput` +| Field | Type | Description | Label | +|-----------------|---------|--------------------------------|--------| +| `period_number` | `int64` | The period number to release. | | + +#### `acs10.SymbolList` +| Field | Type | Description | Label | +|--------|----------|--------------------------------|--------| +| `value`| `string` | The token symbol list. | repeated | + +#### `aelf.Address` +| Field | Type | Description | Label | +|--------|--------|---------------------|--------| +| `value`| `bytes`| | | + +#### `aelf.BinaryMerkleTree` +| Field | Type | Description | Label | +|--------|-------|---------------------|--------| +| `nodes`| `Hash`| The leaf nodes. | | +| `root` | `Hash`| The root node hash. | repeated | +| `leaf_count` | `int32` | The count of leaf node. | | + +#### `aelf.Hash` +| Field | Type | Description | Label | +|--------|--------|---------------------|--------| +| `value`| `bytes`| | | + +#### `aelf.LogEvent` +| Field | Type | Description | Label | +|-------------|--------------|---------------------------------|--------| +| `address` | `Address` | The contract address. | | +| `name` | `string` | The name of the log event. | | +| `indexed` | `bytes` | The indexed data, used to calculate bloom. | repeated | +| `non_indexed` | `bytes` | The non indexed data. | repeated | + +#### `aelf.MerklePath` +| Field | Type | Description | Label | +|-------------------|---------------------|----------------------------|--------| +| `merkle_path_nodes` | `MerklePathNode` | The merkle path nodes. | repeated | + +#### `aelf.MerklePathNode` +| Field | Type | Description | Label | +|--------|--------|----------------------|--------| +| `hash` | `Hash` | The node hash. | | +| `is_left_child_node` | `bool` | Whether it is a left child node. | | + +#### `aelf.SInt32Value` +| Field | Type | Description | Label | +|--------|--------|---------------------|--------| +| `value`| `sint32`| | | + +#### `aelf.SInt64Value` +| Field | Type | Description | Label | +|--------|--------|---------------------|--------| +| `value`| `sint64`| | | + +#### `aelf.ScopedStatePath` +| Field | Type | Description | Label | +|----------|-----------|---------------------|--------| +| `address`| `Address` | The scope address. | | +| `path` | `StatePath`| The path of contract state. | | + +#### `aelf.SmartContractRegistration` +| Field | Type | Description | Label | +|-------------------|--------|-------------------------------|--------| +| `category` | `sint32`| The category of contract code (0: C#). | | +| `code` | `bytes`| The byte array of the contract code. | | +| `code_hash` | `Hash` | The hash of the contract code. | | +| `is_system_contract` | `bool`| Whether it is a system contract. | | +| `version` | `int32`| The version of the current contract. | | + +#### `aelf.StatePath` +| Field | Type | Description | Label | +|----------|--------|-------------------------------|--------| +| `parts` | `string`| The partial path of the state path. | repeated | + +#### `aelf.Transaction` +| Field | Type | Description | Label | +|-------------------|-----------|--------------------------------|--------| +| `from` | `Address` | The address of the sender of the transaction. | | +| `to` | `Address` | The address of the contract when calling a contract. | | +| `ref_block_number`| `int64` | The height of the referenced block hash. | | +| `ref_block_prefix`| `bytes` | The first four bytes of the referenced block hash. | | +| `method_name` | `string` | The name of a method in the smart contract at the To address. | | +| `params` | `bytes` | The parameters to pass to the smart contract method. | | +| `signature` | `bytes` | When signing a transaction, subset of fields: from/to, target method, parameter, reference block number, prefix. | | + +#### `aelf.TransactionExecutingStateSet` +| Field | Type | Description | Label | +|-----------------|---------------------|------------------------------|--------| +| `writes` | `TransactionExecutingStateSet.WritesEntry` | The changed states. | repeated | +| `reads` | `TransactionExecutingStateSet.ReadsEntry` | The read states. | repeated | +| `deletes` | `TransactionExecutingStateSet.DeletesEntry` | The deleted states. | repeated | + +#### `aelf.TransactionExecutingStateSet.DeletesEntry` +| Field | Type | Description | Label | +|--------|--------|---------------------|--------| +| `key` | `string`| | | +| `value`| `bool` | | | + +#### `aelf.TransactionExecutingStateSet.ReadsEntry` +| Field | Type | Description | Label | +|--------|--------|---------------------|--------| +| `key` | `string`| | | +| `value`| `bool` | | | + +#### `aelf.TransactionExecutingStateSet.WritesEntry` +| Field | Type | Description | Label | +|--------|--------|---------------------|--------| +| `key` | `string`| | | +| `value`| `bytes` | | | + +#### `aelf.TransactionResult` +| Field | Type | Description | Label | +|-------------------|-----------|--------------------------------|--------| +| `transaction_id` | `Hash` | The transaction id. | | +| `status` | `TransactionResultStatus` | The transaction result status. | | +| `logs` | `LogEvent`| The log events. | repeated | +| `bloom` | `bytes` | Bloom filter for transaction logs. | repeated | +| `return_value` | `bytes` | The return value of the transaction execution. | | +| `block_number` | `int64` | The height of the block that packages the transaction. | | +| `block_hash` | `Hash` | The hash of the block that packages the transaction. | | +| `error` | `string` | Failed execution error message. | | + +#### `aelf.TransactionResultStatus` +| Name | Number | Description | +|---------------------|--------|-------------------------------------------------------| +| `NOT_EXISTED` | `0` | The execution result of the transaction does not exist. | +| `PENDING` | `1` | The transaction is in the transaction pool waiting to be packaged. | +| `FAILED` | `2` | Transaction execution failed. | +| `MINED` | `3` | The transaction was successfully executed and packaged into a block. | +| `CONFLICT` | `4` | When executed in parallel, there are conflicts with other transactions. | +| `PENDING_VALIDATION`| `5` | The transaction is waiting for validation. | +| `NODE_VALIDATION_FAILED` | `6`| Transaction validation failed. | + +## Usage +ACS10 provides a standardized interface for dividend pools, independent of AElf chain interactions. + +### Implementation + +- Using the Profit Contract +```cs +State.ProfitContract.Value = + Context.GetContractAddressByName(SmartContractConstants.ProfitContractSystemName); +var schemeToken = HashHelper.ComputeFrom(Context.Self); +State.ProfitContract.CreateScheme.Send(new CreateSchemeInput +{ + Manager = Context.Self, + CanRemoveBeneficiaryDirectly = true, + IsReleaseAllBalanceEveryTimeByDefault = true, + Token = schemeToken +}); +State.ProfitSchemeId.Value = Context.GenerateId(State.ProfitContract.Value, schemeToken); +``` + +- Using the TokenHolder Contract +```cs +State.TokenHolderContract.Value = + Context.GetContractAddressByName(SmartContractConstants.TokenHolderContractSystemName); +State.TokenHolderContract.CreateScheme.Send(new CreateTokenHolderProfitSchemeInput +{ + Symbol = Context.Variables.NativeSymbol, + MinimumLockMinutes = input.MinimumLockMinutes +}); +return new Empty(); +``` + +- Donate can be implemented as: +```cs +public override Empty Donate(DonateInput input) +{ + State.TokenContract.TransferFrom.Send(new TransferFromInput + { + From = Context.Sender, + Symbol = input.Symbol, + Amount = input.Amount, + To = Context.Self + }); + State.TokenContract.Approve.Send(new ApproveInput + { + Symbol = input.Symbol, + Amount = input.Amount, + Spender = State.TokenHolderContract.Value + }); + State.TokenHolderContract.ContributeProfits.Send(new ContributeProfitsInput + { + SchemeManager = Context.Self, + Symbol = input.Symbol, + Amount = input.Amount + }); + Context.Fire(new DonationReceived + { + From = Context.Sender, + Symbol = input.Symbol, + Amount = input.Amount, + PoolContract = Context.Self + }); + var currentReceivedDividends = State.ReceivedDividends[Context.CurrentHeight]; + if (currentReceivedDividends != null && currentReceivedDividends.Value.ContainsKey(input.Symbol)) + { + currentReceivedDividends.Value[input.Symbol] = + currentReceivedDividends.Value[input.Symbol].Add(input.Amount); + } + else + { + currentReceivedDividends = new Dividends + { + Value = + { + { + input.Symbol, input.Amount + } + } + }; + } + State.ReceivedDividends[Context.CurrentHeight] = currentReceivedDividends; + Context.LogDebug(() => string.Format("Contributed {0} {1}s to side chain dividends pool.", input.Amount, input.Symbol)); + return new Empty(); +} +``` + +- The method Release directly sends the TokenHolder’s method DistributeProfits transaction: +```cs +public override Empty Release(ReleaseInput input) +{ + State.TokenHolderContract.DistributeProfits.Send(new DistributeProfitsInput + { + SchemeManager = Context.Self + }); + return new Empty(); +} +``` + +- GetSymbolList returns the symbol list recorded in dividend scheme: +```cs +public override SymbolList GetSymbolList(Empty input) +{ + return new SymbolList + { + Value = + { + GetDividendPoolScheme().ReceivedTokenSymbols + } + }; +} +private Scheme GetDividendPoolScheme() +{ + if (State.DividendPoolSchemeId.Value == null) + { + var tokenHolderScheme = State.TokenHolderContract.GetScheme.Call(Context.Self); + State.DividendPoolSchemeId.Value = tokenHolderScheme.SchemeId; + } + return Context.Call( + Context.GetContractAddressByName(SmartContractConstants.ProfitContractSystemName), + nameof(ProfitContractContainer.ProfitContractReferenceState.GetScheme), + State.DividendPoolSchemeId.Value); +} +``` +- Implementation of GetUndistributedDividends returns the balance (same as previous section): +```cs +public override Dividends GetUndistributedDividends(Empty input) +{ + var scheme = GetDividendPoolScheme(); + return new Dividends + { + Value = + { + scheme.ReceivedTokenSymbols.Select(s => State.TokenContract.GetBalance.Call(new GetBalanceInput + { + Owner = scheme.VirtualAddress, + Symbol = s + })).ToDictionary(b => b.Symbol, b => b.Balance) + } + }; +} +``` + +### Test +Testing includes sending Donate, Release transactions, and querying operations. Example: + +- Define the required Stubs: +```cs +const long amount = 10_00000000; +var keyPair = SampleECKeyPairs.KeyPairs[0]; +var address = Address.FromPublicKey(keyPair.PublicKey); +var acs10DemoContractStub = + GetTester(DAppContractAddress, keyPair); +var tokenContractStub = + GetTester(TokenContractAddress, keyPair); +var tokenHolderContractStub = + GetTester(TokenHolderContractAddress, + keyPair); +``` + +- Approve the TokenHolder contract and the dividend pool contract +```cs +await tokenContractStub.Approve.SendAsync(new ApproveInput +{ + Spender = TokenHolderContractAddress, + Symbol = "ELF", + Amount = long.MaxValue +}); +await tokenContractStub.Approve.SendAsync(new ApproveInput +{ + Spender = DAppContractAddress, + Symbol = "ELF", + Amount = long.MaxValue +}); +``` + +- Lock the position to reducethe account balance by 10 ELF: +```cs +await tokenHolderContractStub.RegisterForProfits.SendAsync(new RegisterForProfitsInput +{ + SchemeManager = DAppContractAddress, + Amount = amount +}); +``` + +- Implement Donate to reduce the account balance by another 10 ELF: +await acs10DemoContractStub.Donate.SendAsync(new DonateInput +{ + Symbol = "ELF", + Amount = amount +}); + +- Test the GetUndistributedDividends and GetDividends: +```cs +// Check undistributed dividends before releasing. +{ + var undistributedDividends = + await acs10DemoContractStub.GetUndistributedDividends.CallAsync(new Empty()); + undistributedDividends.Value["ELF"].ShouldBe(amount); +} +var blockchainService = Application.ServiceProvider.GetRequiredService(); +var currentBlockHeight = (await blockchainService.GetChainAsync()).BestChainHeight; +var dividends = + await acs10DemoContractStub.GetDividends.CallAsync(new Int64Value {Value = currentBlockHeight}); +dividends.Value["ELF"].ShouldBe(amount); +``` + +- Release bonus, and test GetUndistributedDividends again: +```cs +await acs10DemoContractStub.Release.SendAsync(new ReleaseInput +{ + PeriodNumber = 1 +}); +// Check undistributed dividends after releasing. +{ + var undistributedDividends = + await acs10DemoContractStub.GetUndistributedDividends.CallAsync(new Empty()); + undistributedDividends.Value["ELF"].ShouldBe(0); +} +``` + +- Account will receive the dividend and will change the balance: +```cs +var balanceBeforeClaimForProfits = await tokenContractStub.GetBalance.CallAsync(new GetBalanceInput +{ + Owner = address, + Symbol = "ELF" +}); +await tokenHolderContractStub.ClaimProfits.SendAsync(new ClaimProfitsInput +{ + SchemeManager = DAppContractAddress, + Beneficiary = address +}); +var balanceAfterClaimForProfits = await tokenContractStub.GetBalance.CallAsync(new GetBalanceInput +{ + Owner = address, + Symbol = "ELF" +}); +balanceAfterClaimForProfits.Balance.ShouldBe(balanceBeforeClaimForProfits.Balance + amount); +``` + +### Example +Implementing ACS10 facilitates building dividend pools on main and side chains. \ No newline at end of file From 0ff3722e4d0d3cf93a1ff289a3251b7c2772dcb2 Mon Sep 17 00:00:00 2001 From: vasmohi Date: Mon, 24 Jun 2024 20:02:20 +0530 Subject: [PATCH 15/16] Updated ACS11 - Cross Chain Consensus Standard --- .../ACS11 - Cross Chain Consensus Standard.md | 142 ++++++++++++++++++ 1 file changed, 142 insertions(+) diff --git a/docs/Reference/ACS Introduction/ACS11 - Cross Chain Consensus Standard.md b/docs/Reference/ACS Introduction/ACS11 - Cross Chain Consensus Standard.md index e69de29..a0d5dd9 100644 --- a/docs/Reference/ACS Introduction/ACS11 - Cross Chain Consensus Standard.md +++ b/docs/Reference/ACS Introduction/ACS11 - Cross Chain Consensus Standard.md @@ -0,0 +1,142 @@ +# ACS11 - Cross Chain Consensus Standard +ACS11 is a standard used to customize consensus mechanisms for cross-chain operations. + +## Interface +Contracts inheriting from ACS11 must implement the following interfaces: + +### Methods +| Method Name | Request Type | Response Type | Description | +|-----------------------------------|----------------------------------|----------------------|-------------------------------------------------| +| `UpdateInformationFromCrossChain` | `google.protobuf.BytesValue` | `google.protobuf.Empty` | Update the consensus information of the side chain. | +| `GetChainInitializationInformation` | `google.protobuf.BytesValue` | `google.protobuf.BytesValue` | Get the current miner list and consensus round information. | +| `CheckCrossChainIndexingPermission` | `aelf.Address` | `google.protobuf.BoolValue` | Verify that the input address is the current miner. | + +### Types + +#### `aelf.Address` +| Field | Type | Description | Label | +|--------|--------|------------------------|--------| +| `value`| `bytes`| | | + +#### `aelf.BinaryMerkleTree` +| Field | Type | Description | Label | +|--------|-------|---------------------|--------| +| `nodes`| `Hash`| The leaf nodes. | | +| `root` | `Hash`| The root node hash. | repeated | +| `leaf_count` | `int32` | The count of leaf node. | | + +#### `aelf.Hash` +| Field | Type | Description | Label | +|--------|--------|---------------------|--------| +| `value`| `bytes`| | | + +#### `aelf.LogEvent` +| Field | Type | Description | Label | +|-------------|--------------|---------------------------------|--------| +| `address` | `Address` | The contract address. | | +| `name` | `string` | The name of the log event. | | +| `indexed` | `bytes` | The indexed data, used to calculate bloom. | repeated | +| `non_indexed` | `bytes` | The non-indexed data. | repeated | + +#### `aelf.MerklePath` +| Field | Type | Description | Label | +|-------------------|---------------------|----------------------------|--------| +| `merkle_path_nodes` | `MerklePathNode` | The merkle path nodes. | repeated | + +#### `aelf.MerklePathNode` +| Field | Type | Description | Label | +|--------|--------|----------------------|--------| +| `hash` | `Hash` | The node hash. | | +| `is_left_child_node` | `bool` | Whether it is a left child node. | | + +#### `aelf.SInt32Value` +| Field | Type | Description | Label | +|--------|--------|---------------------|--------| +| `value`| `sint32`| | | + +#### `aelf.SInt64Value` +| Field | Type | Description | Label | +|--------|--------|---------------------|--------| +| `value`| `sint64`| | | + +#### `aelf.ScopedStatePath` +| Field | Type | Description | Label | +|----------|-----------|---------------------|--------| +| `address`| `Address` | The scope address. | | +| `path` | `StatePath`| The path of contract state. | | + +#### `aelf.SmartContractRegistration` +| Field | Type | Description | Label | +|-------------------|--------|-------------------------------|--------| +| `category` | `sint32`| The category of contract code (0: C#). | | +| `code` | `bytes`| The byte array of the contract code. | | +| `code_hash` | `Hash` | The hash of the contract code. | | +| `is_system_contract` | `bool`| Whether it is a system contract. | | +| `version` | `int32`| The version of the current contract. | | + +#### `aelf.StatePath` +| Field | Type | Description | Label | +|----------|--------|-------------------------------|--------| +| `parts` | `string`| The partial path of the state path. | repeated | + +#### `aelf.Transaction` +| Field | Type | Description | Label | +|-------------------|-----------|--------------------------------|--------| +| `from` | `Address` | The address of the sender of the transaction. | | +| `to` | `Address` | The address of the contract when calling a contract. | | +| `ref_block_number`| `int64` | The height of the referenced block hash. | | +| `ref_block_prefix`| `bytes` | The first four bytes of the referenced block hash. | | +| `method_name` | `string` | The name of a method in the smart contract at the To address. | | +| `params` | `bytes` | The parameters to pass to the smart contract method. | | +| `signature` | `bytes` | Subset of fields: from/to, target method, parameter, reference block number, prefix. | | + +#### `aelf.TransactionExecutingStateSet` +| Field | Type | Description | Label | +|-----------------|---------------------|------------------------------|--------| +| `writes` | `TransactionExecutingStateSet.WritesEntry` | The changed states. | repeated | +| `reads` | `TransactionExecutingStateSet.ReadsEntry` | The read states. | repeated | +| `deletes` | `TransactionExecutingStateSet.DeletesEntry` | The deleted states. | repeated | + +##### `aelf.TransactionExecutingStateSet.DeletesEntry` +| Field | Type | Description | Label | +|--------|--------|---------------------|--------| +| `key` | `string`| | | +| `value`| `bool` | | | + +##### `aelf.TransactionExecutingStateSet.ReadsEntry` +| Field | Type | Description | Label | +|--------|--------|---------------------|--------| +| `key` | `string`| | | +| `value`| `bool` | | | + +##### `aelf.TransactionExecutingStateSet.WritesEntry` +| Field | Type | Description | Label | +|--------|--------|---------------------|--------| +| `key` | `string`| | | +| `value`| `bytes` | | | + +#### `aelf.TransactionResult` +| Field | Type | Description | Label | +|-------------------|-----------|--------------------------------|--------| +| `transaction_id` | `Hash` | The transaction id. | | +| `status` | `TransactionResultStatus` | The transaction result status. | | +| `logs` | `LogEvent`| The log events. | repeated | +| `bloom` | `bytes` | Bloom filter for transaction logs. | repeated | +| `return_value` | `bytes` | The return value of the transaction execution. | | +| `block_number` | `int64` | The height of the block that packages the transaction. | | +| `block_hash` | `Hash` | The hash of the block that packages the transaction. | | +| `error` | `string` | Failed execution error message. | | + +#### `aelf.TransactionResultStatus` +| Name | Number | Description | +|---------------------|--------|-------------------------------------------------------| +| `NOT_EXISTED` | `0` | The execution result of the transaction does not exist. | +| `PENDING` | `1` | The transaction is in the transaction pool waiting to be packaged. | +| `FAILED` | `2` | Transaction execution failed. | +| `MINED` | `3` | The transaction was successfully executed and packaged into a block. | +| `CONFLICT` | `4` | When executed in parallel, there are conflicts with other transactions. | +| `PENDING_VALIDATION`| `5` | The transaction is waiting for validation. | +| `NODE_VALIDATION_FAILED` | `6`| Transaction validation failed. | + +### Example +ACS11 defines methods for customizing consensus mechanisms for cross-chain scenarios. AElf provides an implementation of ACS11 through the AEDPoS contract. Developers can refer to the AEDPoS contract API for implementation details. \ No newline at end of file From 8e1805a10acb9a8956dccdb9933465977d9e205b Mon Sep 17 00:00:00 2001 From: vasmohi Date: Mon, 24 Jun 2024 20:04:55 +0530 Subject: [PATCH 16/16] Updated ACS12 - User Contract Standard --- .../ACS12 - User Contract Standard.md | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/docs/Reference/ACS Introduction/ACS12 - User Contract Standard.md b/docs/Reference/ACS Introduction/ACS12 - User Contract Standard.md index e69de29..927d5d4 100644 --- a/docs/Reference/ACS Introduction/ACS12 - User Contract Standard.md +++ b/docs/Reference/ACS Introduction/ACS12 - User Contract Standard.md @@ -0,0 +1,16 @@ +# ACS12 - User Contract Standard +ACS12 is a standard used to manage user contracts. + +## Types + +### `acs12.UserContractMethodFees` +| Field | Type | Label | Description | +|--------|-------------------------|-----------|----------------------------------------| +| `fees` | `acs12.UserContractMethodFee` | repeated | List of fees to be charged. | +| `is_size_fee_free` | `bool` | | Optional based on the implementation of `SetConfiguration` method. | + +### `acs12.UserContractMethodFee` +| Field | Type | Label | Description | +|-------------|---------|-----------|----------------------------------------| +| `symbol` | `string`| | The token symbol of the method fee. | +| `basic_fee` | `int64` | | The amount of fees to be charged. | \ No newline at end of file