Account Permission Management
Introduction
Account permission management function allows for permission grading, and each permission can correspond to multiple private keys. This makes it possible to achieve multi-person joint control of accounts, and different permissions are managed by different people. This guide walks the user through TRON's account permission management implementation and design.
Design
The scheme includes the three privilege levels of owner, witness, and active. Owner permission has the authority to execute all contracts, witness permission is used for super representative, and active is a custom permission (can be combined with permission sets).
Structure Description
1. Account Modification
message Account {
...
Permission owner_permission = 31;
Permission witness_permission = 32;
repeated Permission active_permission = 33;
}
Three permission attributes are added to the account structure, namely owner_permission, witness_permission, and active_permission, where active_permission is a list and can be specified up to 8.
2. Contract Type Modification
message Transaction {
message Contract {
enum ContractType {
AccountCreateContract = 0;
...
AccountPermissionUpdateContract = 46;
}
}
}
}
Added a transaction type AccountPermissionUpdateContract to update account permissions.
3. AccountPermissionUpdateContract
message AccountPermissionUpdateContract {
bytes owner_address = 1;
Permission owner = 2;
Permission witness = 3;
repeated Permission actives = 4;
}
Parameter | Description |
---|---|
owner_address | The address of the account to be modified |
owner | Modified owner permission |
witness | Modified witness permission (if it is a witness) |
actives | Modified actives permission |
This interface overrides the original account permissions, so if you only want to modify the owner permissions, the witness (if it is a witness account) and actives also need to be set.
4. Permission
message Permission {
enum PermissionType {
Owner = 0;
Witness = 1;
Active = 2;
}
PermissionType type = 1;
int32 id = 2;
string permission_name = 3;
int64 threshold = 4;
int32 parent_id = 5;
bytes operations = 6;
repeated Key keys = 7;//
}
Parameter | Description |
---|---|
PermissionType | Permission type, currently only supports three permissions. |
id | The value is automatically set by the system, with Owner id=0 and Witness id=1. Active id is incremented from 2 onwards. When the contract is executed, the id is used to specify which permission to use. For example, if the owner permission is used, the id is set to 0. |
permission_name | Permission name, set by the user, limited to 32 bytes in length. |
threshold | Threshold, the corresponding operation is allowed only when the sum of the weights of the participating signatures exceeds the domain value. Requires a maximum value less than the Long type. |
parent_id | Currently only 0 |
operations | A total of 32 bytes (256 bits), each representing the authority of a contract, a 1 means the authority to own the contract. Please refer to below detailed example: "Example of operations in active permissions" |
keys | The address and weight that jointly own the permission can be up to 5 keys. |
5. Key
message Key {
bytes address = 1;
int64 weight = 2;
}
Parameter | Description |
---|---|
address | Address with this privilege |
weight | This address has weight for this permission |
6. Transaction Modification
message Transaction {
...
int32 Permission_id = 5;
}
Add a Permission_id
field to the transaction, corresponding to Permission.id
, which specifies which permission to use. The default is 0, which is the owner permission. It is not allowed to be 1, because the witness permission is only used for block creation and is not used to sign the transaction.
Owner Permission
OwnerPermission is the highest privilege of the account, used to control the ownership of the user, adjust the privilege structure, and the Owner privilege can also execute all contracts.
The Owner privilege has the following characteristics:
- The address with OwnerPermission can modify the account's permission.
- When OwnerPermission is empty, the account address is assumed to have owner permission by default.
- When a new account is created, the address of the account is automatically filled into OwnerPermission, and the default threshold value is 1. The keys only contain the account address and the weight is 1.
- When the permissionId is not specified when a transaction is executed, OwnerPermission is used by default.
Witness Permission
The super representative can use this privilege to manage the block-producing nodes. Non-super representative accounts do not have this permission.
Example of usage scenario: A super representative deploys a block-producing node on the cloud server. For account security, you can assign the block production permission to another address. Since the address only has the block production permission, there is no TRX transfer permission, and even if the private key on the server is leaked, TRX will not be lost.
SR's block production node configuration:
- No special configuration is required when the witness permission is not modified.
- After the witness permission of the SR is modified, the block producing node needs to be reconfigured. The configuration items are as follows:
#config.conf
// Optional.The default is empty.
// It is used when the witness account has set the witnessPermission.
// When it is not empty, the localWitnessAccountAddress represents the address of the witness account,
// and the localwitness is configured with the private key of the witnessPermissionAddress in the witness account.
// When it is empty,the localwitness is configured with the private key of the witness account.
// Optional, default is empty.
// Used to set the durationPermission when the witness account is set.
// When the value is not empty, localWitnessAccountAddress represents the address of the witness account, and localwitness is the private key of the address in the durationPermission.
// When the value is empty, localwitness is configured as the private key of the witness account.
//localWitnessAccountAddress =
localwitness = [
f4df789d3210ac881cb900464dd30409453044d2777060a0c391cbdf4c6a4f57
]
Active Permissions
Active permission is used to provide a combination of permissions, such as providing a permission to perform only the creation of accounts and transfer functions.
Active permission has the following features:
- The address with OwnerPermission can modify Active permissions
- The address with the permission to execute AccountPermissionUpdateContract can also modify Active permissions
- Support up to 8 combinations.
- The id of the permission is automatically incremented from 2.
- When a new account is created, an Active permission is automatically created and the address of the account is filled in it. The default threshold value is 1, and the keys only contain the account address and the weight is 1.
Cost
- The fee for updating account permission is 100TRX, that is, the transaction type is AccountPermissionUpdate.
- When a transaction requires multiple accounts' signatures, that is, the transaction includes two or more signatures, in addition to the transaction fee, an additional 1TRX will be charged.
- The above fees are dynamic parameters in the TRON network, and super representatives can modify the value of them by initiating a proposal vote.
API
Modify Permissions
AccountPermissionUpdateContract
, modify the permissions steps are as follows:
- Use the interface
getaccount
to query the account and get the original permissions - Modify the permission
- Create a contract, signature
- Send a transaction
http-demo
http://{{host}}:{{port}}/wallet/accountpermissionupdate
{
"owner_address": "41ffa9466d5bf6bb6b7e4ab6ef2b1cb9f1f41f9700",
"owner": {
"type": 0,
"permission_name": "owner",
"threshold": 2,
"keys": [{
"address": "41F08012B4881C320EB40B80F1228731898824E09D",
"weight": 1
},
{
"address": "41DF309FEF25B311E7895562BD9E11AAB2A58816D2",
"weight": 1
},
{
"address": "41BB7322198D273E39B940A5A4C955CB7199A0CDEE",
"weight": 1
}
]
},
"actives": [{
"type": 2,
"permission_name": "active0",
"threshold": 3,
"operations": "7fff1fc0037e0000000000000000000000000000000000000000000000000000",
"keys": [{
"address": "41F08012B4881C320EB40B80F1228731898824E09D",
"weight": 1
},
{
"address": "41DF309FEF25B311E7895562BD9E11AAB2A58816D2",
"weight": 1
},
{
"address": "41BB7322198D273E39B940A5A4C955CB7199A0CDEE",
"weight": 1
}
]
}]
}
// For the definition and limitations of the parameter fields, please see Structure Description.
Example of operations in active permissions
"operations" is a hexadecimal coded sequence (little-endian byte order), 32 bytes (256 bits), and each bit represents the authority of a system contract type. The nth bit indicates the authority of the system contract type with ID n
, its value 1 means that it has the authority to execute the type of system contract, its value 0 means it has not the authority. Please refer to the table below for the ID values of different system contract types:
System Contract Type | ID | Description |
---|---|---|
AccountCreateContract | 0 | create Account |
TransferContract | 1 | TRX transfer |
TransferAssetContract | 2 | TRC-10 token transfer |
VoteAssetContract | 3 | unused |
VoteWitnessContract | 4 | Vote for Super Representatives |
WitnessCreateContract | 5 | Apply to be a Super Representative Candidate |
AssetIssueContract | 6 | Issue TRC-10 Tokens |
WitnessUpdateContract | 8 | Update website URLs for Super Representative candidates |
ParticipateAssetIssueContract | 9 | Buy TRC-10 Tokens |
AccountUpdateContract | 10 | update account name |
FreezeBalanceContract | 11 | Stake1.0 stake |
UnfreezeBalanceContract | 12 | Unstake TRX staked in Stake1.0 phase |
WithdrawBalanceContract | 13 | Withdraw rewards |
UnfreezeAssetContract | 14 | Unfreeze issued TRC10 tokens |
UpdateAssetContract | 15 | Update TRC10 token parameters |
ProposalCreateContract | 16 | Create proposal |
ProposalApproveContract | 17 | Approve proposal |
ProposalDeleteContract | 18 | Delete propossal |
SetAccountIdContract | 19 | Set account ID |
CreateSmartContract | 30 | Create a smart contract |
TriggerSmartContract | 31 | Trigger smart contract |
UpdateSettingContract | 33 | Update consume_user_resource_percent |
ExchangeCreateContract | 41 | Create an exchange |
ExchangeInjectContract | 42 | Exchange Inject |
ExchangeWithdrawContract | 43 | Exchange Withdraw |
ExchangeTransactionContract | 44 | Bancor Transaction |
UpdateEnergyLimitContract | 45 | Adjust the energy limit provided by the smart contract deployer |
AccountPermissionUpdateContract | 46 | Update account permissions |
ClearABIContract | 48 | Clear contract ABI |
UpdateBrokerageContract | 49 | Update SR Brokerage |
ShieldedTransferContract | 51 | Shielded transactions |
FreezeBalanceV2Contract | 54 | Stake TRX |
UnfreezeBalanceV2Contract | 55 | Unstake TRX |
WithdrawExpireUnfreezeContract | 56 | Withdraw the unstaked principal that has passed the lock-up period |
DelegateResourceContract | 57 | Resource delegate |
UnDelegateResourceContract | 58 | Cancel resource delegate |
CancelAllUnfreezeV2Contract | 59 | Cancel all unstakes |
To make it easier for users to read, take the binary big-endian byte order as an example to illustrate how to calculate the value of operations
: The number of digits starts from 0, and corresponds to the ID of the system contract type from left to right. Convert a binary big-endian byte sequence to a hexadecimal little-endian byte sequence, that will be the value of operations
, please refer to below examples:
Operations Allowed | Binary Code(big-endian) | Binary Code(little-endian) | Hex Code(little-endian) |
---|---|---|---|
TransferContract(1) & VoteWitnessContract(4) | 01001000 00000000 00000000 ... | 00010010 00000000 00000000 ... | 12 00 00 ... |
TransferContract(1) & UpdateAssetContract(15) | 01000000 00000001 00000000 ... | 000000010 10000000 00000000 ... | 02 80 00 ... |
All system contracts | 11111110 11111111 11111000 ... | 01111111 11111111 00011111 ... | 7F FF 1F ... |
Example of calculation of operations in active authority
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.bouncycastle.util.encoders.Hex;
enum ContractType {
UndefinedType(-1),
AccountCreateContract(0),
TransferContract(1),
TransferAssetContract(2),
VoteAssetContract(3),
VoteWitnessContract(4),
WitnessCreateContract(5),
AssetIssueContract(6),
WitnessUpdateContract(8),
ParticipateAssetIssueContract(9),
AccountUpdateContract(10),
FreezeBalanceContract(11),
UnfreezeBalanceContract(12),
WithdrawBalanceContract(13),
UnfreezeAssetContract(14),
UpdateAssetContract(15),
ProposalCreateContract(16),
ProposalApproveContract(17),
ProposalDeleteContract(18),
SetAccountIdContract(19),
CustomContract(20),
CreateSmartContract(30),
TriggerSmartContract(31),
GetContract(32),
UpdateSettingContract(33),
ExchangeCreateContract(41),
ExchangeInjectContract(42),
ExchangeWithdrawContract(43),
ExchangeTransactionContract(44),
UpdateEnergyLimitContract(45),
AccountPermissionUpdateContract(46),
ClearABIContract(48),
UpdateBrokerageContract(49),
ShieldedTransferContract(51),
MarketSellAssetContract(52),
MarketCancelOrderContract(53),
FreezeBalanceV2Contract(54),
UnfreezeBalanceV2Contract(55),
WithdrawExpireUnfreezeContract(56),
DelegateResourceContract(57),
UnDelegateResourceContract(58),
CancelAllUnfreezeV2Contract(59);
private int num;
ContractType(int num) { this.num = num; }
public static ContractType getContractTypeByNum(int num) {
for(ContractType type : ContractType.values()){
if(type.getNum() == num)
return type;
}
return ContractType.UndefinedType;
}
public int getNum() {
return num;
}
}
public class operationsEncoderAndDecoder{
// Description: get operations code according to the input contract types
public static String operationsEncoder(ContractType[] contractId){
List<ContractType> list = new ArrayList<ContractType>(Arrays.asList(contractId));
byte[] operations = new byte[32];
list.forEach(e -> {
int num = e.getNum();
operations[num / 8] |= (1 << num % 8);
});
return Hex.toHexString(operations);
}
// Description: get all allowable contract types according to the operations code
public static List<String> operationsDecoder(String operations){
List<String> contractIDs = new ArrayList<>();
byte[] opArray = Hex.decode(operations);
for(int i=0;i<32;i++) // 32 bytes
{
for(int j=0;j<8;j++)
{
if((opArray[i]>>j & 0x1) ==1) {
contractIDs.add(ContractType.getContractTypeByNum(i*8+j).name());
}
}
}
return contractIDs;
}
public static void main(String[] args) {
ContractType[] contractID = {ContractType.TransferContract, ContractType.VoteWitnessContract, ContractType.FreezeBalanceV2Contract };
String operations = operationsEncoder(contractID);
System.out.println(operations);
// output: 1200000000004000000000000000000000000000000000000000000000000000
List<String> contractIDs = operationsDecoder(operations);
contractIDs.forEach(e ->{
System.out.print(e + " ");
});
// output: TransferContract VoteWitnessContract FreezeBalanceV2Contract
}
}
Construct and execute transaction which created using different permission
- Create a transaction, the same as the construction process of a non-multiple signature transaction
- Specify the Permission_id, the default is 0, indicating the owner-permission
- User A signs the transaction and then sends the signed transaction to B through other means.
- User B signs the transaction and then sends the signed transaction to C via other means.
...
n. The last user who completed the signature broadcasts the transaction to the node.
N+1. The node verifies that the sum of the weights of the signatures is greater than the threshold value, accept the transaction, otherwise reject the transaction
Detailed process please refer to How to create transaction using different account permissions.
Other Permission-Management related Interfaces
Query API related to permission-managed transaction:
- Query Signed Address
curl -X POST http://127.0.0.1:8090/wallet/getapprovedlist -d '{"transaction"}'
rpc GetTransactionApprovedList(Transaction) returns (TransactionApprovedList) { }
- Query Transaction Signature Weight
curl -X POST http://127.0.0.1:8090/wallet/getsignweight -d '{"transaction"}'
rpc GetTransactionSignWeight (Transaction) returns (TransactionSignWeight) {}
The owner-permission and an active-permission are automatically generated during account creation. The owner-permission contains one key, with the permissions and thresholds both set as 1. The active-permission also contains a key with permissions and thresholds set at 1. The operations are "7fff1fc0033efb07000000000000000000000000000000000000000000000000", which means all operations except AccountPermissionUpdateContract are supported.
Updated 12 days ago