bitpro가 원문에서 글자만 모은 내용이에요. 표·그림·수식은 빠지거나 깨질 수 있어요. 전체 41쪽 중 39쪽
r for the creation request to succeed, some assertions must pass:
The Sender can only have one pending request at any time.
The
locked_token_amount
cannot be lower than the indexing price.
If
is_privilege_preserved
is true (exclusive side chain), the token initial issue list cannot be empty and all with an
amount
greater than 0.
If
is_privilege_preserved
is true (exclusive side chain), the
initial_resource_amount
must contain all resource tokens of the chain, and the value must be greater than 0.
The allowance approved to cross-chain contract from the proposer (Sender of the transaction) cannot be lower than the
locked_token_amount
.
No need to provide data about side chain token if
is_privilege_preserved
is false.
var
sideChainCreationRequest
=
async
function
(
crossChainContract
)
{
// call the cross-chain contract to request the creation
const
creationRequestResult
=
await
crossChainContract
.
RequestSideChainCreation
(
{
indexing_price
:
1
,
locked_token_amount
:
20000
,
is_privilege_preserved
:
true
,
side_chain_token_creation_request
:
{
side_chain_token_symbol
:
"MEGA"
,
side_chain_token_name
:
"MEGA"
,
side_chain_token_total_supply
:
100000000
,
side_chain_token_decimals
:
8
,
}
,
side_chain_token_initial_issue_list
:
[
{
address
:
defaultPrivateKeyAddress
,
amount
:
10000000
,
}
,
]
,
initial_resource_amount
:
{
CPU
:
100
,
RAM
:
100
,
DISK
:
100
,
NET
:
100
,
}
,
}
)
;
let
sideChainProposalResult
=
await
pollMining
(
creationRequestResult
.
TransactionId
)
;
let
logs
=
parseLogs
(
sideChainProposalResult
.
Logs
)
;
let
proposalId
=
logs
.
ProposalId
;
}
;
The
cross-chain
contract emits an event containing the
ProposalId
. This is needed for the last step.
Approve the Proposal
This is where the parliament organization members approve the proposal:
var
proposalApproveTx
=
await parliamentContract
.
Approve
(
deserializedLogs
[
0
]
.
proposalId
)
;
await
pollMining
(
proposalApproveTx
.
TransactionId
)
;
Note
: when calling
Approve
it will be the
Sender
of the transaction that approves. Here the script is set to use the key of one parliament organization member, see full script at the end.
Release the Proposal
This part of the script releases the proposal:
var
releaseResult
=
await crossChainContract
.
ReleaseSideChainCreation
(
{
proposalId
:
deserializedLogs
[
0
]
.
proposalId
}
)
;
let
releaseTxResult
=
await
pollMining
(
releaseResult
.
TransactionId
)
;
// Parse the logs to get the chain id.
let
sideChainCreationEvent
=
crossChainContract
.
deserializeLog
(
releaseTxResult
.
Logs
,
'SideChainCreatedEvent'
)
;
This is the last step involved in creating a side chain, after this the chain id of the new side chain is accessible in the
SideChainCreatedEvent
event log.
Complete Script
This script demonstrates the essential steps to create a side chain in the aelf ecosystem. The developer must approve some ELF tokens, request the side chain creation, get approval from the parliament organization, and finally release the proposal to create the side chain. Ensure to set the proper configurations and values as per your blockchain environment.
const
AElf
=
require
(
"aelf-sdk"
)
;
const
Wallet
=
AElf
.
wallet
;
const
{
sha256
}
=
AElf
.
utils
;
// set the private key of the block producer
const
defaultPrivateKey
=
"e119487fea0658badc42f089fbaa56de23d8c0e8d999c5f76ac12ad8ae897d76"
;
const
defaultPrivateKeyAddress
=
"HEtBQStfqu53cHVC3PxJU6iGP3RGxiNUfQGvAPTjfrF3ZWH3U"
;
const
wallet
=
Wallet
.
getWalletByPrivateKey
(
defaultPrivateKey
)
;
// link to the node
const
aelf
=
new
AElf
(
new
AElf
.
providers
.
HttpProvider
(
"http://127.0.0.1:8000"
)
)
;
if
(
!
aelf
.
isConnected
(
)
)
{
console
.
log
(
"Could not connect to the node."
)
;
}
const
tokenContractName
=
"AElf.ContractNames.Token"
;
const
parliamentContractName
=
"AElf.ContractNames.Parliament"
;
const
crossChainContractName
=
"AElf.ContractNames.CrossChain"
;
var
pollMining
=
async
function
(
transactionId
)
{
console
.
log
(
`
>> Waiting for
${
transactionId
}
the transaction to be mined.
`
)
;
for
(
i
=
0
;
i
<
10
;
i
++
)
{
const
currentResult
=
await
aelf
.
chain
.
getTxResult
(
transactionId
)
;
// console.log('transaction status: ' + currentResult.Status);
if
(
currentResult
.
Status
===
"MINED"
)
return
currentResult
;
await
new
Promise
(
(
resolve
)
=>
setTimeout
(
resolve
,
2000
)
)
.
catch
(
function
(
)
{
console
.
log
(
"Promise Rejected"
)
;
}
)
;
}
}
;
var
setAllowance
=
async
function
(
tokenContract
,
crossChainContractAddress
)
{
console
.
log
(
"\n>>>> Setting allowance for the cross-chain contract."
)
;
// set some allowance to the cross-chain contract
const
approvalResult
=
await
tokenContract
.
Approve
(
{
symbol
:
"ELF"
,
spender
:
crossChainContractAddress
,
amount
:
20000
,
}
)
;
await
pollMining
(
approvalResult
.
TransactionId
)
;
}
;
var
checkAllowance
=
async
function
(
tokenContract
,
owner
,
spender
)
{
console
.
log
(
"\n>>>> Checking the cross-chain contract's allowance"
)
;
const
checkAllowanceTx
=
await
tokenContract
.
GetAllowance
.
call
(
{
symbol
:
"ELF"
,
owner
:
owner
,
spender
:
spender
,
}
)
;
console
.
log
(
`
>> allowance to the cross-chain contract:
${
checkAllowanceTx
.
allowance
}
${
checkAllowanceTx
.
symbol
}
`
)
;
}
;
const
createSideChain
=
async
(
)
=>
{
// get the status of the chain in order to get the genesis contract address
console
.
log
(
"Starting side chain creation script\n"
)
;
const
chainStatus
=
await
aelf
.
chain
.
getChainStatus
(
{
sync
:
true
}
)
;
const
genesisContract
=
await
aelf
.
chain
.
contractAt
(
chainStatus
.
GenesisContractAddress
,
wallet
)
.
catch
(
(
err
)
=>
{
console
.
log
(
err
)
;
}
)
;
// get the addresses of the contracts that we'll need to call
const
tokenContractAddress
=
await
genesisContract
.
GetContractAddressByName
.
call
(
sha256
(
tokenContractName
)
)
;
const
parliamentContractAddress
=
await
genesisContract
.
GetContractAddressByName
.
call
(
sha256
(
parliamentContractName
)
)
;
const
crossChainContractAddress
=
await
genesisContract
.
GetContractAddressByName
.
call
(
sha256
(
crossChainContractName
)
)
;
// build the aelf-sdk contract object
const
parliamentContract
=
await
aelf
.
chain
.
contractAt
(
parliamentContractAddress
,
wallet
)
;
const
tokenContract
=
await
aelf
.
chain
.
contractAt
(
tokenContractAddress
,
wallet
)
;
const
crossChainContract
=
await
aelf
.
chain
.
contractAt
(
crossChainContractAddress
,
wallet
)
;
// 1. set and check the allowance, spender is the cross-chain contract
await
setAllowance
(
tokenContract
,
crossChainContractAddress
)
;
await
checkAllowance
(
tokenContract
,
defaultPrivateKeyAddress
,
crossChainContractAddress
)
;
// 2. request the creation of the side chain with the cross=chain contract
console
.
log
(
"\n>>>> Requesting the side chain creation."
)
;
const
sideChainCreationRequestTx
=
await
crossChainContract
.
RequestSideChainCreation
(
{
indexingPrice
:
1
,
lockedTokenAmount
:
"20000"
,
isPrivilegePreserved
:
true
,
sideChainTokenCreationRequest
:
{
sideChainTokenDecimals
:
8
,
sideChainTokenName
:
"SCATokenName"
,
sideChainTokenSymbol
:
"SCA"
,
sideChainTokenTotalSupply
:
"100000000000000000"
,
}
,
sideChainTokenInitialIssueList
:
[
{
address
:
"28Y8JA1i2cN6oHvdv7EraXJr9a1gY6D1PpJXw9QtRMRwKcBQMK"
,
amount
:
"1000000000000000"
,
}
,
]
,
initialResourceAmount
:
{
CPU
:
2
,
RAM
:
4
,
DISK
:
512
,
NET
:
1024
}
,
}
)
;
let
sideChainCreationRequestTxResult
=
await
pollMining
(
sideChainCreationRequestTx
.
TransactionId
)
;
// deserialize the log to get the proposal's ID.
let
deserializedLogs
=
parliamentContract
.
deserializeLog
(
sideChainCreationRequestTxResult
.
Logs
,
"ProposalCreated"
)
;
console
.
log
(
`
>> side chain creation request proposal id
${
JSON
.
stringify
(
deserializedLogs
[
0
]
.
proposalId
)
}
`
)
;
// 3. Approve the proposal
console
.
log
(
"\n>>>> Approving the proposal."
)
;
var
proposalApproveTx
=
await
parliamentContract
.
Approve
(
deserializedLogs
[
0
]
.
proposalId
)
;
await
pollMining
(
proposalApproveTx
.
TransactionId
)
;
// 3. Release the side chain
console
.
log
(
"\n>>>> Release the side chain."
)
;
var
releaseResult
=
await
crossChainContract
.
ReleaseSideChainCreation
(
{
proposalId
:
deserializedLogs
[
0
]
.
proposalId
,
}
)
;
let
releaseTxResult
=
await
pollMining
(
releaseResult
.
TransactionId
)
;
// Parse the logs to get the chain id.
let
sideChainCreationEvent
=
crossChainContract
.
deserializeLog
(
releaseTxResult
.
Logs
,
"SideChainCreatedEvent"
)
;
console
.
log
(
"Chain chain created : "
)
;
console
.
log
(
sideChainCreationEvent
)
;
}
;
createSideChain
(
)
.
then
(
(
)
=>
{
console
.
log
(
"Done."
)
;
}
)
;
Note
: Replace the placeholders in the script with actual values and logic for your use case.
Running a Side Chain
Description
: A tutorial on how to configure and run a side chain node in the aelf blockchain ecosystem after its creation has been approved.
Purpose
: To guide developers through the setup and launch process of a side chain node, ensuring correct configuration and successful integration with the main chain.
This tutorial explains how to run a side chain node after it has been approved by the producers and released by the creator. After creating the side chain, producers need to run a side chain node.
Prerequisites
You already have a main-chain node running.
The creation of the side chain has been approved and released.
Important Note
The key-pair (account) used for mining on the side chain must be the same as the one used on the main-chain node. Both production nodes need to be launched with the same key-pair.
Side Chain Configuration
Configuration Files
Two configuration files must be placed in the configuration folder of the side chain, from which you will launch the node:
appsettings.json
appsettings.SideChain.MainNet.json
Chain ID and Settings
After the release of the side chain creation request, the ChainId of the new side chain will be accessible in the SideChainCreatedEvent logged by the transaction that released it.
In this example, we will set up the side chain node with ChainId
tDVV
(1866392 converted to base58), connecting to Redis
db2
, and using web API port
1235
. Don’t forget to change the
account
,
password
, and
initial miner
.
appsettings.json
{
"ChainId"
:
"tDVV"
,
"ChainType"
:
"SideChain"
,
"NetType"
:
"MainNet"
,
"ConnectionStrings"
:
{
"BlockchainDb"
:
"redis://localhost:6379?db=2"
,
"StateDb"
:
"redis://localhost:6379?db=2"
}
,
"Account"
:
{
"NodeAccount"
:
"YOUR PRODUCER ACCOUNT"
,
"NodeAccountPassword"
:
"YOUR PRODUCER PASSWORD"
}
,
"Kestrel"
:
{
"EndPoints"
:
{
"Http"
:
{
"Url"
:
"http://*:1235/"
}
}
}
,
"Consensus"
:
{
"MiningInterval"
:
4000
,
"StartTimestamp"
:
0
}
}
appsettings.SideChain.MainNet.json
{
"CrossChain"
:
{
"Grpc"
:
{
"ParentChainServerPort"
:
5010
,
"ListeningPort"
:
5000
,
"ParentChainServerIp"
:
"127.0.0.1"
}
,
"ParentChainId"
:
"AELF"
}
}
Change
ParentChainServerIp
and
ParentChainServerPort
depending on the listening address of your mainchain node.
Launching the Side Chain Node
Open a terminal and navigate to the folder where you created the side chain configuration:
Terminal
dotnet
..
/AElf.Launcher.dll
You can try out a few commands from another terminal to check if everything is fine, for example:
Terminal
aelf-command get-blk-height
-e
http://127.0.0.1:1235
Side Chain Creation API
API for Proposing Side Chain Creation
Side Chain Types
Paying for Side Chain
Indexing Fee
Resource Fee
Simple Demo for Side Chain Creation Request
Step-by-Step Code Snippets
Set-Up
Creation of the Side Chain
Complete Script
Running a Side Chain
Prerequisites
Important Note
Side Chain Configuration
Launching the Side Chain Node
## /quick-start/node-operators/run-aelf-on-cloud
On this page
This guide will walk you through the steps required to run an aelf node on Google Cloud Platform (GCP).
Step 1: Launch aelf Image
Go to the
Google Cloud Marketplace
and search for "aelf blockchain for enterprise".
Find the aelf image and click on "LAUNCH ON COMPUTE ENGINE".
Keep the default settings and click "DEPLOY" at the bottom left of the page.
Step 2: Access and Start the Chain
Login to the launched VM instance via SSH. You can do this by clicking the SSH drop-down and selecting "Open in browser window".
In the SSH session, execute
sudo bash
to elevate your privileges.
Start the chain with one of the following commands:
Run it in the foreground:
cd
/opt/aelf-node
&&
docker-compose
up
Or run it in the background:
cd
/opt/aelf-node
&&
docker-compose
up
-d
Step 3: Verify Chain Status
To verify that the node is working, use the following command to send an HTTP request and get the current chain status:
curl
-X
GET
"http://127.0.0.1:8001/api/blockChain/chainStatus"
-H
"accept: text/plain; v=1.0"
If everything is working normally, you should see the chain status increase with each request.
Step 1: Launch aelf Image
Step 2: Access and Start the Chain
Step 3: Verify Chain Status
## /learn/core
📄️
Core Introduction
Overview of aelf, its architecture, and key features.
📄️
Core Implementation
Design Principles
## /learn/cross-chain
📄️
Introduction
aelf's cross-chain functionalities
📄️
Architecture
aelf's cross-chain system architecture
📄️
Cross Chain Verification
aelf's cross-chain verification process
📄️
Verify
Verification methods for aelf cross-chain
📄️
Cross Chain Transfer
Performing cross-chain transfers in aelf
## /learn/consensus
On this page
Consensus
Overview
Consensus is crucial for blockchains as it decides which transactions are included in the block and their order. aelf's block formation mechanism is more complex than Bitcoin and Ethereum due to its need to record Side Chain data and its cloud-based service design. Miners must update info from multiple parallel Chains. aelf uses AEDPoS consensus for high-frequency and predictable block formation.
How aelf Consensus Works:
Election
: Determines who gets to produce blocks.
Scheduling
: Decides when those blocks are produced.
Core Data Center
Core Data Centers, also known as Miners or Block Producers, act like parliament members in the aelf blockchain. aelf has 2N+1 Core Data Centers, starting with 8 and increasing by 1 each year. These nodes enforce aelf’s consensus rules, relay transactions, confirm transactions, package blocks, and transfer data. They also act as miners for some Side Chains and are elected by ELF token holders.
Validate Data Center
Anyone can join the election by locking ELF tokens. The top (2N+1)*5 nodes become Validate Data Centers, with N starting at 8 and increasing by 1 each year.
AEDPoS Process
Round
aelf operates in units called "rounds." In each round, one Core Data Center produces one block and has one extra transaction at the end.
Main Processes
Pre-Verification
Before generating blocks in round (t+1), a node’s status in round t is verified by checking
hash(in_node(t)) = out_node(t)
.
Order Calculation
In each round, Core Data Centers have (N+1) block generation time slots.
The order and signature for each node in the first round are arbitrary. From the second round, the signature is calculated using
sig_node(t+1) = hash(in_node(t) + all_t)
where
Here node[i][t], means the node is processing the i-th transaction in round t.
From round 3, the order is based on the previous round’s order and signature. In round (t+1), we traverse the signature of nodes at round t in order. The ordering of a node in (t+1) is calculated by
If conflicts occur, the node is assigned to the next available place. The extra transaction node is calculated from the first place node's signature of the previous round.
Timing
Nodes have 4 seconds to process transactions. Failure to submit within this time results in a penalty. If a node fails twice consecutively, it enters a penalty period, increasing exponentially with each failure.
Fork Handling
Only one node generates blocks at a time to avoid forks. If multiple orphan nodes occur, the longest chain is adopted. Vicious nodes mining in two chains are voted out.
Irreversible Block
Some block links (block height to hash value) are irreversible, confirmed by the AEDPoS mechanism during round changes.
Overview
Core Data Center
Validate Data Center
AEDPoS Process
Round
Main Processes
Irreversible Block
## /learn/network
On this page
Network
Introduction
The network layer in aelf is vital for maintaining connections and communication between nodes. It supports higher-level logic like synchronization and allows node operators to monitor and manage network operations. aelf uses gRPC for connections to keep the design simple and flexible.
Architecture
The network consists of three layers:
aelf.OS
Handles network events.
Runs background tasks for network operations.
aelf.OS.Core.Network
Provides services to higher levels.
Defines infrastructure components and types.
aelf.OS.Network.Grpc
Implements the infrastructure layer using gRPC.
Manages low-level functions like serialization and retrying.
aelf.OS
This layer monitors and handles network-related events:
Transaction Accepted Event
: When a transaction is verified.
Block Mined Event
: When a block is packaged.
Block Accepted Event
: When a block is executed successfully.
New Irreversible Block Found Event
: When a new irreversible block is found.
It also performs regular tasks:
Peer Health Check
: Ensures connected peers are healthy.
Peer Retry Connection
: Attempts to reconnect with unhealthy peers.
Network Node Discovery
: Finds new nodes.
aelf.OS.Core.Network
This core module includes:
NetworkService
: Manages sending/receiving requests, broadcasting items to peers, and handling network exceptions.
IPeerPool/PeerPool
: Manages active peer connections.
IPeer
: Defines peer interactions and metrics.
IaelfNetworkServer
: Manages network lifecycle and connections.
aelf.OS.Network.Grpc
Implements the infrastructure layer using gRPC:
GrpcPeer
: Implements
IPeer
.
GrpcStreamPeer
: Client-side
IPeer
implementation (node version >=1.4.0).
GrpcStreamBackPeer
: Server-side
IPeer
implementation (node version >=1.4.0).
GrpcNetworkServer
: Implements
IaelfNetworkServer
.
GrpcServerService
: Manages network service interfaces and data exchange.
Extra functionalities include:
Serializing and deserializing requests.
Implementing request/response mechanisms.
Authentication.
Protocol
Nodes use a defined network interface protocol for normal operation and data synchronization.
Connection
DoHandshake
When a node connects, it exchanges handshake information. This includes chain status, current height, and more.
Request
:
rpc
DoHandshake
(
HandshakeRequest
)
returns
(
HandshakeReply
)
{
}
Handshake Message
:
message
Handshake
{
HandshakeData
handshake_data
=
1
;
bytes
signature
=
2
;
bytes
session_id
=
3
;
}
HandshakeData Message
:
message
HandshakeData
{
int32
chain_id
=
1
;
int32
version
=
2
;
int32
listening_port
=
3
;
bytes
pubkey
=
4
;
aelf
.
Hash
best_chain_hash
=
5
;
int64
best_chain_height
=
6
;
aelf
.
Hash
last_irreversible_block_hash
=
7
;
int64
last_irreversible_block_height
=
8
;
google
.
protobuf
.
Timestamp
time
=
9
;
}
ConfirmHandshake
Confirms the handshake with the target node.
Request
:
rpc
ConfirmHandshake
(
ConfirmHandshakeRequest
)
returns
(
VoidReply
)
{
}
Broadcasting
BlockBroadcastStream
Receives bloc프로젝트로 돌아가기