# Tài liệu của Klaytn

{% hint style="info" %}
This is the archived documentation for Klatyn, which is no longer maintained. For up-to-date documentation, visit our [new doc site](https://docs.klaytn.foundation/vi/).
{% endhint %}

Tài liệu của Klaytn giới thiệu về [Klaytn](http://klaytn.foundation), một nền tảng cấp doanh nghiệp, lấy dịch vụ làm trọng tâm, mang đến cho hàng triệu người dùng trải nghiệm chuỗi khối thân thiện với người dùng.

Hãy đọc [Tóm tắt bản cáo bạch](https://klaytn.foundation/wp-content/uploads/Lightpaper.pdf) của chúng tôi.

<table data-view="cards"><thead><tr><th></th><th></th><th></th><th data-hidden data-card-cover data-type="files"></th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td><strong>Tổng quan về Klaytn</strong></td><td>Bạn muốn tìm hiểu về Klaytn?</td><td></td><td><a href="/files/WWuRHz3ukEEyKRHUC6A4">/files/WWuRHz3ukEEyKRHUC6A4</a></td><td><a href="/pages/Aywmflj60sn3kuaCMTo0">/pages/Aywmflj60sn3kuaCMTo0</a></td></tr><tr><td><strong>Bắt đầu</strong></td><td>Bạn muốn bắt đầu xây dựng trên Klaytn?</td><td></td><td><a href="/files/0AvcKZmFbhIMMXHNrQQe">/files/0AvcKZmFbhIMMXHNrQQe</a></td><td><a href="/pages/J8fEVmca3iYAMlW6KQoW">/pages/J8fEVmca3iYAMlW6KQoW</a></td></tr><tr><td><strong>Người vận hành nút</strong></td><td>Hướng dẫn về cách vận hành nút của Klaytn</td><td></td><td><a href="/files/nDb7sbXdQu3XvGGxEhIa">/files/nDb7sbXdQu3XvGGxEhIa</a></td><td><a href="/pages/Yu8Fzg24ifMQ34EkET2G">/pages/Yu8Fzg24ifMQ34EkET2G</a></td></tr><tr><td><strong>Klaytn tuyệt vời</strong></td><td>Danh sách đầy đủ các tài nguyên trong hệ sinh thái rộng lớn của Klaytn</td><td></td><td><a href="/files/hNe6Ye6a5WEsq78jqkrO">/files/hNe6Ye6a5WEsq78jqkrO</a></td><td><a href="https://github.com/klaytn/awesome-klaytn">https://github.com/klaytn/awesome-klaytn</a></td></tr><tr><td><strong>Trung tâm nhà phát triển Klaytn</strong></td><td>Cổng thông tin nhà phát triển Klaytn</td><td></td><td><a href="/files/rCbtkCEjIK00BBxFvldQ">/files/rCbtkCEjIK00BBxFvldQ</a></td><td><a href="http://developer.klaytn.foundation">http://developer.klaytn.foundation</a></td></tr><tr><td><strong>Diễn đàn nhà phát triển Klaytn</strong></td><td>Bạn có câu hỏi? Hãy truy cập diễn đàn của chúng tôi!</td><td></td><td><a href="/files/087b1GMPxy9sMAuLc71I">/files/087b1GMPxy9sMAuLc71I</a></td><td><a href="http://forum.klaytn.foundation">http://forum.klaytn.foundation</a></td></tr></tbody></table>


# Tổng quan về Klaytn

Klaytn là một chuỗi khối công khai, dựa trên BFT, được tối ưu hóa cao nhằm đáp ứng độ tin cậy ở cấp doanh nghiệp. Các mục tiêu thiết kế chính là;

* Tính hoàn thiện tức thời.
* TPS cao đáp ứng các trường hợp sử dụng trong thực tế.
* Giảm chi phí chạy các ứng dụng chuỗi khối.
* Giảm thiểu các rào cản tham gia cho người dùng cuối.
* Đơn giản hóa quá trình áp dụng công nghệ trong ngành.

Klaytn khởi chạy mạng chính thức [Cypress](https://scope.klaytn.com/) của mình vào ngày 27 tháng 6 năm 2019 với các thông số kỹ thuật sau.

* Thời gian tạo và xác nhận khối 1 giây.
* 4.000 giao dịch mỗi giây.
* Giá gas thấp, gần bằng 1/10 Ethereum.
* Chạy EVM (Máy ảo Ethereum) và hỗ trợ thực thi các hợp đồng Solidity.
* 19 tập đoàn uy tín trên toàn thế giới đã thành lập Hội đồng quản trị của Klaytn từ ban đầu để vận hành các nút đồng thuận. Số lượng nút đồng thuận hiện tại được nêu trong [Klaytnscope](https://scope.klaytn.com/).
* Hơn 50 đối tác dịch vụ ban đầu đã cam kết khởi chạy các ứng dụng chuỗi khối trên Klaytn.

## Klaytn: Bức tranh toàn cảnh <a href="#klaytn-the-big-picture" id="klaytn-the-big-picture"></a>

Klaytn có thể được phân vùng thành ba mạng con logic dựa trên vai trò và mục đích của chúng. Hình dưới đây hiển thị chế động xem cấp cao của hệ sinh thái Klaytn.

![Hệ sinh thái Klaytn và các mạng con logic (CNN, ENN, SCN)](/files/Y5OhwrsmdZj2QmBnSjGc)

### Mạng Core Cell (CCN) <a href="#core-cell-network-ccn" id="core-cell-network-ccn"></a>

CCN có chứa các Core Cell (CC) xác thực và thực thi các giao dịch được gửi qua các Nút điểm cuối (EN). CCN chịu trách nhiệm tạo và truyền các khối trong mạng.

### Mạng lưới nút điểm cuối (ENN) <a href="#endpoint-node-network-enn" id="endpoint-node-network-enn"></a>

ENN bao gồm các Nút điểm cuối (EN) chủ yếu tạo giao dịch, xử lý các yêu cầu API RPC và xử lý các yêu cầu dữ liệu từ chuỗi dịch vụ.

### Mạng lưới chuỗi dịch vụ (SCN) <a href="#service-chain-network-scn" id="service-chain-network-scn"></a>

SCN là các mạng con của Klaytn có chứa các chuỗi khối phụ trợ được vận hành độc lập bởi dApp (Ứng dụng phi tập trung). Các chuỗi dịch vụ được kết nối với chuỗi chính thông qua các EN.

**Mạng Core Cell** và **Mạng lưới nút điểm cuối** tạo nên chuỗi chính của Klaytn, hay mạng chính thức. Các ứng dụng chuỗi khối có thể chạy trên chuỗi chính của Klaytn, Cypress hoặc có thể vận hành trên các chuỗi khối của riêng chúng, được gọi là **Chuỗi dịch vụ**. Nếu bạn muốn có một môi trường thực thi riêng cho ứng dụng của mình, đảm bảo có TPS cao và các chính sách mạng lưới cấu hình được, chúng tôi khuyến khích bạn nên dùng Chuỗi dịch vụ.

> Để thiết lập một Chuỗi dịch vụ cho ứng dụng của mình, hãy đọc phần [hướng dẫn cài đặt và vận hành Chuỗi dịch vụ](/content/installation-guide/deployment/service-chain/getting-started).

## Mô hình cấu trúc mạng lưới Klaytn <a href="#klaytn-network-topology" id="klaytn-network-topology"></a>

Trong phần này, chúng tôi sẽ mô tả mô hình cấu trúc chuỗi chính của Klaytn. Một kiến trúc mạng theo tầng với các loại nút dựa trên vai trò, được triển khai trong Klaytn nhằm tối ưu hóa hiệu suất mạng.

### Các loại nút dựa trên vai trò <a href="#role-based-node-types" id="role-based-node-types"></a>

Trước khi tìm hiểu về mô hình cấu trúc chuỗi chính của Klaytn, chúng ta cần làm quen với các loại nút khác nhau của Klaytn.

#### Core Cell (CC): Nút đồng thuận (CN) + Nút Proxy (PN) <a href="#core-cell-cc-consensus-node-cn-proxy-node-pn" id="core-cell-cc-consensus-node-cn-proxy-node-pn"></a>

Một Core Cell (CC) được tạo thành bởi một **Nút đồng thuận (CN)** duy nhất và hai **Nút proxy (PN)**. Nút đồng thuận tham gia vào quá trình tạo khối, trong khi Nút proxy cung cấp giao diện cho mạng. Nút proxy chuyển yêu cầu giao dịch đến Nút đồng thuận và truyền các khối xuống Nút điểm cuối.

> Nếu bạn muốn trở thành Người vận hành Core Cell, hãy đọc phần [hướng dẫn cài đặt và vận hành Core Cell](/content/installation-guide/deployment/core-cell/installation-guide/before-you-install).

#### Nút điểm cuối (EN) <a href="#endpoint-node-en" id="endpoint-node-en"></a>

EN đóng vai trò là điểm cuối cho mạng lưới Klaytn xử lý các yêu cầu API RPC và xử lý dữ liệu gửi đến và từ các chuỗi dịch vụ.

> Để thiết lập Nút điểm cuối cho ứng dụng của bạn, hãy đọc phần [hướng dẫn cài đặt và vận hành Nút điểm cuối](/content/installation-guide/deployment/endpoint-node).

#### Nút ban đầu <a href="#bootnode" id="bootnode"></a>

Nút ban đầu là một loại nút đặc biệt được Klaytn vận hành để giúp các nút mới tham gia đăng ký vào mạng lưới và để khám phá các nút khác nhằm kết nối cùng. Nút ban đầu CN nằm trong CNN và không công khai, còn các nút ban đầu PN và EN thì công khai. Các nút ban đầu PN chỉ cho phép các PN được cấp quyền đăng ký và cho phép các PN đủ điều kiện kết nối với các EN. Các nút ban đầu EN cung cấp cho EN thông tin về các PN cần kết nối.

### Mạng phân tầng <a href="#tiered-networks" id="tiered-networks"></a>

CN, PN và EN lần lượt tạo thành các mạng logic, Mạng nút đồng thuận (CNN), Mạng nút proxy (PNN) và Mạng lưới nút điểm cuối (ENN).

Hình bên dưới hiển thị mô hình cấu trúc tổng thể của mạng chính thức của Klaytn, trong đó mạng Core Cell (CCN) được chia nhỏ thành Mạng nút đồng thuận (CNN) và Mạng nút proxy (PNN). Mạng lưới nút điểm cuối (ENN) cũng được hiển thị dưới dạng mạng xung quanh được kết nối trực tiếp với PNN.

![Klaytn Main Chain Physical Topology and Tiered Architecture (CNN, PNN, and ENN)](/files/lMTPOM0EwnRDtGQES2E1)

#### Mạng nút đồng thuận (CNN) <a href="#consensus-node-network-cnn" id="consensus-node-network-cnn"></a>

CN hình thành một mạng lưới đầy đủ gọi là CNN. CNN áp dụng BFT trên WAN (mạng diện rộng) và cần mỗi CN đáp ứng [các yêu cầu nghiêm ngặt về phần cứng và tài nguyên mạng](/content/installation-guide/deployment/core-cell/system-requirements) để thực hiện đồng thuận BFT ở mức hiệu suất vừa đủ.

#### Mạng nút proxy (PNN) <a href="#proxy-node-network-pnn" id="proxy-node-network-pnn"></a>

PNN có chứa các PN. Thông thường, các PN chỉ duy trì một kết nối với một PN trong Core Cell lân cận. Số lượng kết nối ngang hàng có thể thay đổi tùy thuộc vào cấu hình mạng.

#### Mạng lưới nút điểm cuối (ENN) <a href="#endpoint-node-network-enn" id="endpoint-node-network-enn"></a>

Mạng con ngoài cùng, ENN, chỉ bao gồm các EN được kết nối.

## Tạo và truyền khối <a href="#block-generation-and-propagation" id="block-generation-and-propagation"></a>

Thiết kế tạo và truyền khối, cùng với thuật toán đồng thuận được sử dụng, đó một vai trò quan trọng trong việc giảm thiểu độ trễ của một nền tảng chuỗi khối

### Chu kỳ tạo khối <a href="#block-generation-cycle" id="block-generation-cycle"></a>

Trong Klaytn, chu kỳ tạo khối được goi là "vòng". Mỗi vòng tạo ra một khối mới và một vòng mới bắt đầu ngay sau đó. Klaytn đặt mục tiêu mỗi vòng kéo dài khoảng một giây, mặc dù khoảng thời gian tạo khối có thể bị ảnh hưởng bởi lưu lượng mạng và điều kiện hoạt động của nút.

#### Lựa chọn ủy bạn và người đề xuất <a href="#proposer-and-committee-selection" id="proposer-and-committee-selection"></a>

Trong mỗi vòng, Klaytn ngẫu nhiên nhưng chắc chắn chọn một Nút đồng thuận (CN) làm người đề xuất khối được tạo, sau đó chọn một nhóm CN làm ủy ban cho vòng đó. Klaytn không liên quan trực tiếp đến việc chọn người đề xuất hay ủy ban; thay vào đó, mỗi CN sử dụng một con số ngẫu nhiên lấy từ tiêu đề của khối gần đây nhất để chạy một hoạt động mã hóa, tạo bằng chứng rằng CN đã (hoặc chưa) được chọn cho vòng này. Quy mô của ủy ban phải chống lỗi Byzantine; nếu quy mô của CNN ở mức nhỏ, thì tất cả các CN (trừ người đề xuất) sẽ đủ điều kiện để được chọn làm thành viên ủy ban.

#### Đề xuất và xác thực khối <a href="#block-proposal-and-validation" id="block-proposal-and-validation"></a>

Khi đã được chọn, người đề xuất sẽ phân phối bằng chứng lựa chọn của mình cho vòng đó (nghĩa là bằng chứng mật mã có thể xác thực bằng mã khóa công khai của người đề xuất) cho tất cả các CN. Sau đó, các CN được lựa chọn làm ủy ban cho vòng nhất định sẽ phản hồi người đề xuất bằng những bằng chứng lựa chọn của riêng họ, thông báo cho người đề xuất về việc ai là người sẽ phân phối khối mới sắp được đề xuất. Sau đó, người đề xuất sẽ chọn một tập hợp các giao dịch từ bể giao dịch và tạo khối bằng các sắp xếp chúng. Cuối cùng, người đề xuất thực thi sự đồng thuận với ủy ban để đồng ý và hoàn tất khối mới được tạo. Lưu ý rằng Klaytn có kế hoạch liên tục cải tiến thuật toán đồng thuận để đạt được độ bảo mật và hiệu quả cao hơn.

### Truyền khối <a href="#block-propagation" id="block-propagation"></a>

Một khối phải nhận được chữ ký từ hơn hai phần ba thành viên ủy ban để được hoàn tất thành công. Khi ủy ban đạt được sự đồng thuận, khối mới sẽ được truyền đến tất cả các CN và vòng đồng thuận kết thúc. Khi khối mới được truyền đến tất cả các CN, thông tin của khối mới được tạo có thể được cung cấp cho tất cả những người tham gia mạng lưới Klaytn nhờ cung cấp tiêu đề khối và dữ liệu nội dung cho ENN thông qua PNN.

## Công bố công khai và xác thực mở <a href="#public-disclosure-and-open-validation" id="public-disclosure-and-open-validation"></a>

Các nhà cung cấp dịch vụ và người dùng cuối trên mạng lưới Klaytn có thể tự do xác thực kết quả tạo khối và kiểm tra xem ủy ban CN có tạo khối đó có theo các thủ tục phù hợp hay không. Việc xác thực như vậy bao gồm kiểm tra xem tiêu đề khối có chứa nhiều hơn hai phần ba chữ ký của thành viên ủy ban hay không. Tất cả các CN phải hỗ trợ việc xác thực mở và bắt buộc phải đăng tải mã khóa công khai của họ (được dùng để ký các khối) trong một không gian có thể truy cập công khai (ví dụ như tiêu đề khối). Việc xác thực mở sẽ thúc đẩy tính minh bạch, ngăn chặn việc cắt bỏ thông tin và ngăn ngừa các hành vi độc hại.

## Các kênh truyền riêng biệt cho các khối và giao dịch (truyền đa kênh) <a href="#separated-propagation-channels-for-blocks-and-transactions-multichannel-propagat" id="separated-propagation-channels-for-blocks-and-transactions-multichannel-propagat"></a>

Độ trễ của một mạng chịu ảnh hưởng rất lớn bởi mức độ nghẽn mạng. Giả sử thông lượng của một mạng duy trì không đổi, số lượng giao dịch tăng lên sẽ khiến độ trễ của mạng bị trễ tương ứng. Độ trễ là một vấn đề nghiêm trọng trong các dApp; người dùng thông thường của các ứng dụng di động hoặc dịch vụ web cũ sẽ không chấp nhận thời gian phản hồi mất nhiều hơn vài giây và các dịch vụ chuỗi khối không có lý do gì để cho rằng người dùng có khả năng chấp nhận mức cao hơn.

Klaytn áp dụng hướng tiếp cận đa kênh để xử lý các vấn đề nghẽn mạng. Bằng cách chỉ định các kênh truyền riêng cho giao dịch và khối, mạng lưới Klaytn có thể kịp thời truyền các khối mới tạo, ngay cả khi mạng đang bị nghẽn nghiêm trọng với số lượng giao dịch lớn. Bằng cách này, Klaytn đảm bảo rằng các dApp trên mạng của nó có thể luôn phản hồi các yêu cầu từ người dùng cuối, bất kể lưu lượng truy cập mạng có lúc tăng đột biến.

## Phần thưởng khối <a href="#block-rewards" id="block-rewards"></a>

Đối với mỗi vòng, phần thưởng khối (tổng của 6,4 KLAY mới tạo và phí giao dịch được trả để xử lý khối) sẽ được phân bổ cho những người tham gia mạng theo tỷ lệ phân phối đặt trước. Người đề xuất của khối mới được tạo sẽ nhận được 100% phần thưởng được trao cho các CN, còn ủy ban sẽ không nhận được gì. Lưu ý rằng xác suất của việc được chọn làm người đề xuất chịu ảnh hưởng của số lượng KLAY được nắm giữ bởi CN, nghĩa là một CN có càng nhiều KLAY được đầu tư vào nền tảng thì sẽ có xác suất nhận được nhiều phần thưởng hơn. Bạn có thể xem chi tiết về việc phân phối phần thưởng khối trong phần [Nền kinh tế token của Klay](/content/klaytn/design/token-economy).


# Tại sao nên chọn Klaytn

Tài liệu này giải thích về sự khác biệt của Klaytn dựa trên các nguyên tắc thiết kế chủ đạo của nó.

## Klaytn với vai trò là lớp tin cậy của vũ trụ ảo <a href="#klaytn-as-a-trust-layer-of-metaverse" id="klaytn-as-a-trust-layer-of-metaverse"></a>

Klaytn được xây dựng để trở thành lớp tin cậy căn bản cho vũ trụ ảo, hoạt động tham gia và đóng góp đến từ tất cả các cộng đồng, trao quyền và gắn kết họ với nhau trong thế giới mới. Nguyên tắc thiết kế ưu tiên hàng đầu là

{% hint style="success" %}
Giúp những người tiên phong dễ dàng xây dựng ứng dụng và tổ chức cộng đồng theo cách có thể mở rộng.
{% endhint %}

Theo nguyên tắc này, Klaytn đã được thiết kế để đáp ứng những yêu cầu sau:

### Hiệu suất cao <a href="#high-performance" id="high-performance"></a>

#### Thông lượng (TPS) và Tính hoàn thiện <a href="#throughput-and-finality" id="throughput-and-finality"></a>

* Chuỗi chính cần xử lý tối thiểu 4.000 TPS.
* Chuỗi chính cần đảm bảo tính hoàn thiện giao dịch tức thời với thời gian tạo khối là một giây.
* Xem phần [Cơ chế đồng thuận](/content/klaytn/design/consensus-mechanism).

#### Khả năng mở rộng <a href="#scalability" id="scalability"></a>

* Chuỗi dịch vụ là giải pháp L2 mặc định dành cho Klaytn 2.0, có thể tùy chỉnh và dễ dàng triển khai. Chuỗi dịch vụ có thể được quản trị riêng và kết nối với chuỗi chính của Klaytn để neo dữ liệu hoặc chuyển giao tài sản.
* Xem phần [Chuỗi dịch vụ](/content/klaytn/scaling-solutions#service-chain). Các doanh nghiệp hoặc mạng lưới quy mô lớn thường muốn có môi trường thực thi của riêng họ. Với chuỗi dịch vụ, họ có thể duy trì một môi trường thực thi hiệu suất cao và biệt lập, không bị ảnh hưởng bởi các ứng dụng chuỗi khối khác.
* Các giải pháp khác về khả năng mở rộng sẽ được ra mắt trong tương lai gần, chẳng hạn như sharding (phân đoạn) hoặc rollup (cuộn).

### Chi phí thấp <a href="#low-cost" id="low-cost"></a>

* Người dùng cuối không cần phải gánh bất kỳ khoản phí giao dịch nào cao hơn những gì hệ thống truyền thống yêu cầu.
* Phí giao dịch phải ổn định và được xác định bởi chính độ phức tạp của giao dịch, không phải bởi các yếu tố xung quanh.
* Xem phần [Chi phí thực thi hợp đồng thông minh hợp lý](/content/klaytn/design/computation/klaytn-smart-contract#affordable-smart-contract-execution-cost) và [Phí giao dịch](/content/klaytn/design/transaction-fees). Đối với giá gas ở mức 250 ston, một giao dịch chuyển KLAY sẽ phát sinh chi phí cố định là 0,00525 KLAY. (21.000 gas cho giao dịch chuyển KLAY x (250 x 10^-9) == 0.00525 KLAY)

### Phát triển nhanh chóng <a href="#rapid-development" id="rapid-development"></a>

#### Tương thích với Ethereum <a href="#ethereum-compatibility" id="ethereum-compatibility"></a>

* Các công cụ phát triển: Bất kỳ công cụ nào có thể chạy trên Ethereum cũng sẽ chạy trơn thu trong hệ sinh thái Klaytn bằng cách làm cho tập hợp kỹ thuật của Klaytn trở nên tương đương với tập hợp kỹ thuật hiện có của Ethereum, từ góc độ giao dịch cho đến thực thi. Công cụ mới được tạo ra trong hệ sinh thái Klaytn có thể được áp dụng đối ứng trong hệ sinh thái Ethereum.
* EVM và API: Bằng cách xây dựng trên các tập hợp kỹ thuật có sẵn của Etherum, chúng tôi được thừa hưởng các cải tiến được thực hiện đối với cơ sở mã nguồn mở của EVM và các thư viện hỗ trợ. Bằng việc hỗ trợ các Mã vận hành và logic tập hợp kỹ thuật tương đương như vậy trong môi trường EVM Klaytn, ta sẽ thấy hoạt động thực thi cũng được đảm bảo tương đương; và bằng việc hỗ trợ một tập hợp API JSON-RPC với cú pháp vận chuyển điểm cuối tương đương cũng sẽ đảm bảo tính tương đương của giao diện Ethereum đầy đủ. Xem phần [Solidity-Ngôn ngữ hợp đồng thông minh](/content/smart-contract/solidity-smart-contract-language) và [Chuyển ứng dụng Ethereum sang Klaytn](/content/dapp/tutorials/migrating-ethereum-app-to-klaytn).
* Đóng góp phát triển cốt lõi: Việc hỗ trợ tính tương đương với Ethereum sẽ chuyển đồi hầu hết các giao dịch chung đến cả hai hệ sinh thái Klaytn và Ethereum. Hầu hết các Đề xuất cải tiến Ethereum (EIP) đều có thể được chuyển và áp dụng vào chương trình phát triển cốt lõi của Klaytn, ngược lại, các Đề xuất cải tiến Klaytn (KIP) cũng có thể đóng góp vào sự tiến bộ của Ethereum và EVM. Khi cộng đồng phát triển đóng góp cho một hệ sinh thái, họ thực sự đang đóng góp cho cả hai.

#### Cơ sở hạ tầng nguồn mở và gói <a href="#open-source-infrastructure-and-package" id="open-source-infrastructure-and-package"></a>

* Cơ sở hạ tầng chính: bộ công cụ để tích hợp và xây dựng chuỗi khối toàn diện. Cơ sở hạ tầng này bao gồm SDK và thư viện hợp đồng thông minh, Ví và trình khám phá chuỗi, các giải pháp lưu trữ phân tán, hỗ trợ Oracle và Cầu nối.
* Cơ sở hạ tầng phụ: hệ sinh thái hỗ trợ các sản phẩm và dịch vụ. Cơ sở hạ tầng này bao gồm các dịch vụ Tích hợp/trừu tượng, tích hợp Stablecoin, DAO, Thị trường NFT, DEX và DeFi, cũng như các giao dịch tài chính truyền thống.

### Trải nghiềm người dùng nâng cao <a href="#enhanced-user-experience" id="enhanced-user-experience"></a>

#### Khả năng sử dụng trong giao dịch <a href="#usability-in-transaction" id="usability-in-transaction"></a>

* Khả năng chuyển phí giao dịch của người dùng vào ứng dụng
* Xem phần [Ủy thác phí](/content/klaytn/design/transactions#fee-delegation). Người vận hành ứng dụng có thể điều chỉnh số tiền tài trợ cho mỗi giao dịch và triển khai các mô hình kinh doanh linh hoạt hơn, ví dụ như freemium (chỉ miễn phí các tính năng cơ bản) hoặc đăng ký trả phí định kỳ. Việc ủy thác phí sẽ gỡ bỏ bớt các rào cản thu hút người dùng một cách hiệu quả.

### Quỹ sinh thái cấp giao thức trọn bộ <a href="#contribution-reward" id="contribution-reward"></a>

* Klaytn là ví dụ tiên phong lớn nhất về các ưu đãi hỗ trợ hệ sinh thái được mã hóa trong một nền kinh tế token theo giao thức chuỗi. 50% of the newly minted tokens are reinvested in the ecosystem.
* See [Klaytn Community Fund](/content/klaytn/design/token-economy#klaytn-community-fund) and [Klaytn Foundation Fund](/content/klaytn/design/token-economy#klaytn-foundation-fund).

### Cùng xây dựng cộng đồng <a href="#community-co-building" id="community-co-building"></a>

* Ngoài thiết kế giao thức, Klaytn sẽ mở rộng lĩnh vực của mình thông việc cùng xây dựng cộng đồng; trong đó bao gồm các loại cộng đồng như hội nhóm trò chơi, DAO đầu tư, DAO cộng đồng, liên minh với người chơi toàn cầu, v.v. Cuối cùng là các quy tắc cơ bản:

{% hint style="success" %}
Klaytn không đánh đổi các đặc tính cốt lõi của chuỗi khối để đạt được những điểm cải tiến nêu trên và giao thức vẫn sẽ ổn định với các bên liên quan có cam kết bền chặt.
{% endhint %}

### Minh bạch, bảo mật và phi tập trung <a href="#transparency-security-and-decentralization" id="transparency-security-and-decentralization"></a>

* Ai cũng có thể yêu cầu giao dịch, cũng như truy xuất và xác nhận kết quả giao dịch trên chuỗi khối.
* Klaytn là một mạng phi tập trung, tại đó không có bất kỳ nút độc hại nào có thể phá vỡ tính toàn vẹn của dữ liệu.

### Quản trị bởi DAO, các nhà xây dựng và doanh nghiệp thực hiện phi tập trung với khả năng ổn định <a href="#governance-by-trusted-entities" id="governance-by-trusted-entities"></a>

* Ngoài các doanh nghiệp truyền thống hiện tại đang đóng vai trò Hội đồng quản trị của Klaytn (GC), nhờ việc đưa nhiều thực thể phi tập trung hơn như DAO và các nhà xây dựng vào GC, chúng tôi đang mở ra tiềm năng xây dựng lại toàn bộ cấu trúc quản trị của Klaytn một cách chưa từng có tiền lệ với hàng trăm người tham gia vào hoạt động quản trị.


# Thiết kế của Klaytn


# Cơ chế đồng thuận

Cơ chế đồng thuận (thuật toán) là cách để đạt được sự đồng thuận giữa các thực thể mà không cần đến sự tin tưởng. Trong công nghệ chuỗi khối, cơ chế này được sử dụng để đạt được sự đồng thuận về việc một khối có hợp lệ hay không. Hiệu suất của các mạng chuỗi khối phụ thuộc vào hiệu suất của các cơ chế đồng thuận đã được thông qua và nó có tác động đáng kể đến khả năng sử dụng cảm nhận của các Ứng dụng chuỗi khối.

Mạng chính thức Cypress của Klaytn có hiệu suất như sau.

* Xử lý hơn 4.000 giao dịch mỗi giây.
* Hoàn thiện giao dịch tức thời.
* Thời gian tạo khối một giây.
* Hơn 50 nút đồng thuận có thể tham gia vào quá trình đồng thuận.

Trong tài liệu này, chúng ta sẽ tìm hiểu cách áp dụng quy trình đồng thuận hiệu suất cao của Klaytn.

## Thông tin cơ bản <a href="#background" id="background"></a>

[Bitcoin](https://en.wikipedia.org/wiki/Bitcoin) đang sử dụng [PoW](https://en.wikipedia.org/wiki/Proof_of_work) (Bằng chứng công việc), trong khi Ethereum gần đây đã chuyển qua [PoS](https://en.wikipedia.org/wiki/Proof_of_stake) (Bằng chứng cổ phần), cơ chế này sẽ quyết định về các nút tạo khối bằng cổ phần của nút. Thông thường, các thuật toán này không cần đến hoạt động giao tiếp giữa các nút trong việc quyết định về tính hợp lệ của các khối.

Vì thế, trong các hệ thống này, một phân nhánh có thể phát sinh, nghĩa là có thể có từ hai khối khác nhau trở lên được tạo ra với cùng một chiều cao. Thông thường, quy tắc "chuỗi nào dài nhất sẽ là chuỗi hợp lệ" được áp dụng để xử lý tình trạng phân nhánh. Điều này có nghĩa là các phân nhánh này cuối cùng sẽ được hợp nhất thành một chuỗi chính tắc duy nhất, nhưng điều này cũng có nghĩa là danh sách các khối có thể được hoàn nguyên sau một khoảng thời gian nào đó khi nó thuộc về chuỗi ngắn hơn. Vì thế, trong các thuật toán này, không có gì đảm bảo được tính hoàn thiện của các khối và giao dịch. Tính hoàn thiện chỉ có thể đạt được theo xác suất sau một khoảng thời gian, điều này vẫn không thể được đảm bảo 100%.

Tình trạng thiếu tính hoàn thiện này là một vấn đề khó khăn đối với các dịch vụ lấy khách hàng làm trọng tâm có sử dụng nền tảng chuỗi khối. Điều này xảy ra là vì cần phải đợi cho đến khi các phân nhánh được giải quyết và có đủ khối được tạo ra sau giao dịch chuyển tiền để tin rằng giao dịch không thể đảo ngược. Điều này có tác động tiêu cực đến cả người dùng và nhà cung cấp dịch vụ.

Các dịch vụ tài chính có thể làm ví dụ minh họa đơn giản cho vấn đề này. Giả sử một người dùng chuyển tiền cho người khác và dịch vụ này không thể xác minh rằng giao dịch chuyển tiền đó là hợp lệ trong 30 đến 60 phút. Điều này xảy ra là vì cần phải đợi cho đến khi các phân nhánh đã được hợp nhất thành một chuỗi duy nhất và có một số khối đã được tạo ra sau giao dịch chuyển tiền để đảm bảo rằng giao dịch đó không thể đảo ngược.

### PBFT (Hệ thống chịu lỗi Byzantine thiết thực) <a href="#pbft-practical-byzantine-fault-tolerance" id="pbft-practical-byzantine-fault-tolerance"></a>

Để ngăn ngừa các vấn đề trên, chúng ta cần các thuật toán khác, đảm bảo được tính hoàn thiện. Thuật toán BFT là một trong số đó, được [ra mắt](https://dl.acm.org/citation.cfm?doid=357172.357176) lần đầu vào năm 1982 bởi Lamport, Shostak, Pease. Vào năm 1999, Miguel Castro và Barbara Liskov giới thiệu "Hệ thống chịu lỗi Byzantine thiết thực"([PBFT](http://www.pmg.csail.mit.edu/papers/bft-tocs.pdf)) cung cấp tính năng nhân bản máy trạng thái hiệu suất cao.

Trong thuật toán PoW được nêu ở trên, mặc dù mỗi nút đều nhận và xác thực các khối, không có sự trao đổi thông báo giữa các nút để đạt được sự đồng thuận. Tuy nhiên, trong PBFT, mỗi nút đều giao tiếp với các nút tham gia khác để đạt được sự đồng thuận và tính hoàn thiện của khối cũng có thể được đảm bảo ngay khi các nút có thể đạt được sự đồng thuận.

Hoạt động giao tiếp giữa các nút về cơ bản diễn ra như sau. Tuy nhiên, có một số biến thể phản ánh đặc điểm của từng hệ thống.

![Luồng thông báo của PBFT](/files/GSpw38zknsoqGKQWoyJm)

Như đã nêu ở trên, về cơ bản, một nút tham gia trong PBFT giao tiếp với tất cả các nút trong mạng tại một số giai đoạn. Đặc tính này giới hạn số lượng nút vì khối lượng giao tiếp tăng theo cấp số nhân khi số lượng nút tăng lên.

## Cơ chế đồng thuận trong Klaytn <a href="#consensus-mechanism-in-klaytn" id="consensus-mechanism-in-klaytn"></a>

Klaytn mong muốn trở thành một nền tảng lấy dịch vụ làm trọng tâm và sẵn sàng cho doanh nghiệp. Do đó, chúng ta cần giải quyết vấn đề về tính hoàn thiện đã nêu ở trên và mạng sẽ có thể cho phép nhiều nút tham gia vào mạng. Để thực hiện được điều này, Klaytn đang sử dụng phiên bản tối ưu hóa của Istanbul BFT, phiên bản này triển khai PBFT với một số sửa đổi để xử lý các đặc tính của mạng chuỗi khối.

Trong Klaytn, có ba loại nút, CN (Nút đồng thuận), ON (Nút proxy) và EN (Nút điểm cuối). CN được quản lý bởi các CCO (Người vận hành Core Cell) và chịu trách nhiệm tạo khối. Các khối này được xác minh bởi tất cả các nút trong mạng. Vui lòng tham khảo [ở đây](/content/klaytn#klaytn-network-topology) để tìm hiểu thêm về mô hình cấu trúc mạng này.

![Cấu trúc liên kết mạng](/files/lMTPOM0EwnRDtGQES2E1)

Klaytn đạt được tính hoàn thiện nhanh nhờ việc áp dụng và cải thiện Istanbul BFT. Do việc xác thực và đồng thuận được thực hiện cho mỗi khối nên sẽ không phát sinh hiện tượng phân nhánh, đồng thời, tính hoàn thiện của khối được đảm bảo ngay lập tức sau khi đạt được sự đồng thuận.

Ngoài ra, vấn đề về việc tăng khối lượng giao tiếp trong thuật toán BFT cũng được giải quyết bằng cách sử dụng `Ủy ban` được chọn ngẫu nhiên. Các CN cùng nhau tạo thành một `Hội đồng` và với mỗi lần tạo khối, một phần trong số này được chọn làm thành viên của `Ủy ban` bằng cách sử dụng VRF (Chức năng ngẫu nhiên có thể xác minh).

![Khái niệm về hội đồng và ủy ban](/files/5K05gZ50bIIUT1k0s5Jb)

Do các thông báo về đồng thuận chỉ được trao đổi giữa các thành viên ủy ban, nên khối lượng giao tiếp có thể bị giới hạn dưới mức thiết kế, mặc dù tổng số các CN tăng lên.

Hiện tại, mạng chính thức của Klaytn, Cypress, có thể cung cấp thông lượng cao ở mức 4000 giao dịch mỗi giây, với khoảng thời gian tạo khối là một giây. Hiện tại, hơn 50 nút đồng thuận có thể tham gia vào CNN (Mạng nút đồng thuận) và con số này sẽ liên tục tăng lên khi Klaytn tiếp tục tích cực tối ưu hóa thuật toán.


# Tài khoản

## Tài khoản Klaytn <a href="#klaytn-accounts" id="klaytn-accounts"></a>

### Tổng quan về tài khoản, trạng thái và địa chỉ <a href="#overview-of-account-state-and-address" id="overview-of-account-state-and-address"></a>

Tài khoản trong Klaytn là một cấu trúc dữ liệu chứa thông tin về số dư của một người hoặc một hợp đồng thông minh. Trạng thái của Klaytn là tập hợp của tất cả các trạng thái của tài khoản trong đó - nghĩa là trạng thái trong quá khứ và hiện tại của tất cả các dữ liệu được lưu trữ trong tất cả các tài khoản của Klaytn. Khi một giao dịch được thực thi trên một nút Klaytn, thì kết quả là trạng thái của Klaytn sẽ thay đổi trên khắp tất cả các nút. Trạng thái của các nút trong mạng lưới Klaytn phải giống nhau nếu chúng đã xử lý các khối giống nhau có cùng thứ tự. Thông tin trạng thái của mỗi tài khoản được liên kết với địa chỉ 20 byte, địa chỉ này được dùng để định danh từng tài khoản.

### Tách các cặp khóa khỏi địa chỉ <a href="#decoupling-key-pairs-from-addresses" id="decoupling-key-pairs-from-addresses"></a>

Một tài khoản là một nền tảng chuỗi khối điển hình liên kết với một địa chỉ đã xử lý mã hóa với độ dài nhất định, thường có dạng: "0x0fe2e20716753082222b52e753854f40afddffd2". Địa chỉ này được gắn chặt với một cặp khóa. Nếu đã chọn một cặp khóa, địa chỉ sẽ được lấy từ mã khóa công khai. Về mặt trải nghiệm người dùng, việc này có nhiều bất lợi. Dưới đây là một số bất lợi đó:

* Người dùng không thể có địa chỉ mong muốn.
* Người dùng không thể dùng nhiều cặp khóa khác nhau để tăng cường bảo mật cho tài khoản của họ.
* Người dùng không thể thay đổi cặp khóa của tài khoản khi mã khóa riêng tư vô tình bị lộ, hoặc khi người dùng muốn cập nhật mã khóa riêng tư định kỳ để tăng cường bảo mật cho tài khoản.

Đây là những rào cản lớn khiến người dùng không thể coi địa chỉ là mã định danh trong nền tảng chuỗi khối. Để gỡ bỏ rào cản này, Klaytn hỗ trợ một tính năng cho phép người dùng chọn địa chỉ và cặp khóa của họ. Với tính năng này, người dùng có thể chọn địa chỉ mong muốn và họ có thể dùng nhiều cặp khóa khác nhau để tăng cường bảo mật. Số lượng cặp khóa có thể là một hoặc nhiều hơn và các cặp khóa có thể giữ các vai trò khác nhau. Để biết thêm thông tin chi tiết về nhiều cặp khóa hoặc các mã khóa theo vai trò, vui lòng tham khảo phần \[Nhiều cặp khóa & khóa theo vai trò]\(tài khoảns.md#multiple-key-pairs-and-role-based-keys).

Bạn cũng nên lưu ý rằng Klaytn còn hỗ trợ phiên bản cũ, trong đó một cặp khóa và một địa chỉ được liên kết chặt chẽ với nhau.

### Nhiều cặp khóa và khóa theo vai trò <a href="#multiple-key-pairs-and-role-based-keys" id="multiple-key-pairs-and-role-based-keys"></a>

Như đã mô tả ở trên, khi một mã khóa riêng tư bị đánh cắp, bị lộ hoặc bị xâm phạm theo cách nào đó, bạn không thể làm gì để khôi phục tính bảo mật của tài khoản: tùy chọn tốt nhất là tạo một cặp khóa khác để tạo một tài khoản mới, rồi chuyển số dư từ tài khoản cũ bị xâm nhập sang tài khoản mới đó. Việc thiếu sự hỗ trợ cho các phương án dùng khóa nâng cao, ví dụ như đa chữ ký hoặc khóa dành riêng cho từng trường hợp sử dụng lại là một sự bất tiện đáng kể khác. Để giải quyết các vấn đề đó theo cách hiệu quả hơn, tài khoản Klaytn mang đến những khả năng sau:

* Tài khoản Klaytn cho phép thay đổi cặp khóa được liên kết với tài khoản.
* Tài khoản Klaytn hỗ trợ nhiều cặp khóa, cùng với khả năng chỉ định từng khóa cho các mục đích khác nhau.
* Tài khoản Klaytn duy trì khả năng tương thích với các tài khoản chỉ có một khóa được liên kết chặt chẽ với địa chỉ.

Bằng cách tận dụng khả năng hỗ trợ nhiều khóa theo vai trò của tài khoản Klaytn, người dùng cuối có thể xử lý tốt hơn các tình huống rủi ro về bảo mật trong thực tế, ví dụ như quản lý sai cách mã khóa riêng. Ví dụ, khi một người dùng nhận thấy mã khóa riêng tư của mình đã bị lộ, người dùng này chỉ cần thay thế mã khóa riêng tư bị lộ bằng cách xóa cặp khóa bị lộ khỏi tài khoản của mình và tạo một cặp khóa mới thay thế. Để thực hiện được điều này, chúng ta có thể dùng khóa dành riêng được dùng để cập nhật thông tin tài khoản, được tạo trước và lưu trữ riêng biệt với khóa riêng tư bị xâm phạm.

### Địa chỉ mà con người đọc được (HRA) <a href="#human-readable-address-hra" id="human-readable-address-hra"></a>

Mặc dù mô hình địa chỉ (ví dụ: "0x0fe2e20716753082222b52e753854f40afddffd2") có điểm mạnh riêng ở chỗ mô hình này bảo vệ hiệu quả quyền riêng tư của chủ tài khoản nhưng cũng gây ra vấn đề lớn về trải nghiệm của người dùng cuối. Trước tiên, não bộ con người rất khó ghi nhớ hoặc thậm chí là nhận ra những địa chỉ như vậy, do đó, lỗi nhập địa chỉ cũng như nhiều lỗi chủ quan khác nhau rất dễ xảy ra, dẫn đến thiệt hại tài chính không nhỏ. Thứ hai, mô hình địa chỉ như vậy sẽ tước mất quyền lựa chọn cách xử lý danh tính theo cách riêng của người dùng cuối để họ có thể dễ ghi nhớ hoặc sử dụng. Kết hợp lại, những vấn đề này là một trong những rào cản khiến người dùng cuối thông thường (những người đã quen với trải nghiệm người dùng đơn giản và mượt mà hơn do các ứng dụng hoặc dịch vụ di động cũ mang đến) coi trải nghiệm người dùng dApp là xa lạ, khó hiểu và vô cùng bất tiện. Để vượt qua các thách thức như vậy mà không cần thay đổi kiến trúc ở quy mô lớn, đồng thời vẫn duy trì khả năng tương thích ngược, Klaytn đã chọn cung cấp tính năng ánh xạ giữa địa chỉ 20 byte với chuỗi văn bản có độ dài 20 byte, nhờ đó, người dùng cuối có thể chỉ định các giá trị mà họ mong muốn. Tính năng này trong Klaytn được gọi là địa chỉ mà con người đọc được (HRA). Hiện tại, tính năng này vẫn đang trong giai đoạn phát triển và chúng tôi sẽ cung cấp thêm thông tin khi tính năng này sẵn sàng cho việc sử dụng.

### Định dạng khóa của ví Klaytn <a href="#klaytn-wallet-key-format" id="klaytn-wallet-key-format"></a>

Định dạng khóa của ví Klaytn được cung cấp giúp dễ dàng xử lý mã khóa riêng tư kèm theo địa chỉ tương ứng. Điều này sẽ giúp người dùng dễ dàng hơn trong việc duy trì mã khóa riêng tư của mình cùng địa chỉ. Định dạng là `0x{private key}0x{type}0x{address in hex}` ở dạng ký hiệu thập lục phân, trong đó `{type}` phải là `00`. Các giá trị khác giữ nguyên. Dưới đây là ví dụ:

```
0x45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d80x000xa94f5374fce5edbc8e2a8697c15331677e6ebf0b
```

Định dạng này hiện được hỗ trợ trong [Ví Klaytn](/content/dapp/developer-tools/getting-started/klaytn-wallet).

### Các loại tài khoản Klaytn <a href="#klaytn-account-types" id="klaytn-account-types"></a>

Có hai loại tài khoản trong Klaytn: tài khoản sở hữu bên ngoài (\EOA) và tài khoản hợp đồng thông minh (SCA).

#### Tài khoản sở hữu bên ngoài (EOAs) <a href="#externally-owned-accounts-eoas" id="externally-owned-accounts-eoas"></a>

Tài khoản sở hữu bên ngoài chứa các thông tin như số dư và số dùng một lần. Loại tài khoản này không có mã hoặc hệ thống lưu trữ. EOA được kiểm soát bằng khóa riêng tư và không có mã liên kết với chúng. EOA có thể được tạo bằng cặp khóa và nhờ đó, được kiểm soát bởi bất kỳ ai có cặp khóa đó. Khóa tài khoản được mô tả trong phần \[Khóa tài khoản]\(tài khoảns.md#tài khoản-key).

**Thuộc tính**

| Thuộc tính      | type                       | Mô tả                                                                                                                                                                                                                                                                                                                                                                                                                                                |
| --------------- | -------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| type            | uint8 (Go)                 | Loại tài khoản sở hữu bên ngoài. Giá trị này phải là **0x1** đối với EOA.                                                                                                                                                                                                                                                                                                                                                                            |
| số dùng một lần | uint64 (Go)                | Một chuỗi số dùng để xác định thứ tự giao dịch. Giao dịch cần xử lý tiếp theo sẽ có cùng số dùng một lần với giá trị này.                                                                                                                                                                                                                                                                                                                            |
| số dư           | \*big.Int (Go)             | Số lượng KLAY có trong tài khoản.                                                                                                                                                                                                                                                                                                                                                                                                                    |
| humanReadable   | bool (Go)                  | Giá trị boolean cho biết tài khoản được liên kết với một địa chỉ mà con người đọc được. Vì \[HRA]\(tài khoảns.md#human-readable-address-hra) vẫn đang trong quá trình phát triển nên giá trị này đối với mọi tài khoản sẽ là false.                                                                                                                                                                                                                  |
| khóa            | [AccountKey](#account-key) | Khóa liên kết với tài khoản này. Trường này có thể là bất kỳ khóa nào trong số \[AccountKeyLegacy]\(tài khoảns.md#tài khoảnkeylegacy), \[AccountKeyPublic]\(tài khoảns.md#tài khoảnkeypublic), \[AccountKeyFail]\(tài khoảns.md#tài khoảnkeyfail), \[AccountKeyWeightedMultisig]\(tài khoảns.md#tài khoảnkeyweightedmultisig), \[AccountKeyRoleBased]\(tài khoảns.md#tài khoảnkeyrolebased). Chữ ký trong các giao dịch được xác thực bằng khóa này. |

#### Tài khoản hợp đồng thông minh (SCA) <a href="#smart-contract-accounts-scas" id="smart-contract-accounts-scas"></a>

Trái ngược với EOA, SCA có mã liên kết với chung và được kiểm soát bằng mã này. SCA được tạo ra bằng các giao dịch triển khai hợp đồng thông minh; khi đã được triển khai, SCA không thể tự mình khởi tạo giao dịch mới và phải được một tài khoản khác kích hoạt, tài khoản EOA hoặc SCA.

**Thuộc tính**

| Thuộc tính      | type                       | Mô tả                                                                                                                                                                                                                                                                                                                                                                                                                                                |
| --------------- | -------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| type            | uint8 (Go)                 | Loại tài khoản hợp đồng thông minh. Giá trị này phải là **0x2** đối với SCA.                                                                                                                                                                                                                                                                                                                                                                         |
| số dùng một lần | uint64 (Go)                | Một chuỗi số dùng để xác định thứ tự giao dịch. Giao dịch cần xử lý tiếp theo sẽ có cùng số dùng một lần với giá trị này.                                                                                                                                                                                                                                                                                                                            |
| số dư           | \*big.Int (Go)             | Số lượng KLAY có trong tài khoản.                                                                                                                                                                                                                                                                                                                                                                                                                    |
| humanReadable   | bool (Go)                  | Giá trị boolean cho biết tài khoản được liên kết với một địa chỉ mà con người đọc được. Vì \[HRA]\(tài khoảns.md#human-readable-address-hra) vẫn đang trong quá trình phát triển nên giá trị này đối với mọi tài khoản sẽ là false.                                                                                                                                                                                                                  |
| khóa            | [AccountKey](#account-key) | Khóa liên kết với tài khoản này. Trường này có thể là bất kỳ khóa nào trong số \[AccountKeyLegacy]\(tài khoảns.md#tài khoảnkeylegacy), \[AccountKeyPublic]\(tài khoảns.md#tài khoảnkeypublic), \[AccountKeyFail]\(tài khoảns.md#tài khoảnkeyfail), \[AccountKeyWeightedMultisig]\(tài khoảns.md#tài khoảnkeyweightedmultisig), \[AccountKeyRoleBased]\(tài khoảns.md#tài khoảnkeyrolebased). Chữ ký trong các giao dịch được xác thực bằng khóa này. |
| codeHash        | \[]byte (Go)               | Hàm băm của mã hợp đồng thông minh của tài khoản. Giá trị này là bất biến, nghĩa là nó chỉ được đặt khi hợp đồng thông minh được tạo.                                                                                                                                                                                                                                                                                                                |
| storageRoot     | \[32]byte (Go)             | Hàm băm 256 bit của gốc của Merkle Patricia Trie có chứa các giá trị của tất cả các biến về lưu trữ trong tài khoản.                                                                                                                                                                                                                                                                                                                                 |
| codeFormat      | uint8 (Go)                 | Hỗ trợ phiên bản trình thông dịch. Có thể đặt tối đa 16. Hiện tại chỉ hỗ trợ EVM(0x00).                                                                                                                                                                                                                                                                                                                                                              |
| vmVersion       | uint8 (Go)                 | Thông tin nâng cấp giao thức (nâng cấp căn bản) vào thời điểm triển khai hợp đồng (ví dụ: 0x0(constantinople), 0x1(istanbul,london,...)). Có thể sử dụng tối đa 16. Có thể được tạo tự động cùng với hợp đồng.                                                                                                                                                                                                                                       |

{% hint style="success" %}
LƯU Ý: Kể từ klaytn v1.7.0 trở đi, thuộc tính vmVersion sẽ được thêm vào tài khoản hợp đồng thông minh.
{% endhint %}

### Mã loại tài khoản Klaytn <a href="#klaytn-account-type-id" id="klaytn-account-type-id"></a>

Dưới đây là mã loại tài khoản được chỉ định cho từng loại tài khoản.

| Loại tài khoản                      | Mã loại tài khoản |
| ----------------------------------- | ----------------- |
| Tài khoản sở hữu bên ngoài (EOA)    | 0x1               |
| Tài khoản hợp đồng thông minh (SCA) | 0x2               |

## Khóa tài khoản <a href="#account-key" id="account-key"></a>

Khóa tài khoản tương ứng với cấu trúc khóa liên kết với một tài khoản.

### AccountKeyNil <a href="#accountkeynil" id="accountkeynil"></a>

AccountKeyNil tương ứng với một khóa trống. Nếu một tài khoản cố sử dụng đối tượng AccountKeyNil, thì giao dịch sẽ không thành công. AccountKeyNil chỉ được dùng cho các giao dịch TxTypeAccountUpdate với các khóa theo vai trò. Ví dụ, nếu một tài khoản chỉ muốn cập nhật khóa RoleAccountUpdate, thì trường khóa của giao dịch TxTypeAccountUpdate sẽ là:

`[AccountKeyNil, NewKey, AccountKeyNil]`

Sau đó, chỉ có khóa RoleAccountUpdate mới được cập nhật. Các vai trò khác không được cập nhật. Tham khảo \[AccountKeyBased]\(tài khoảns.md#tài khoảnkeyrolebased) để biết thêm thông tin.

#### Thuộc tính <a href="#attributes" id="attributes"></a>

Không có thuộc tính cho AccountKeyNil.

#### Mã hóa RLP <a href="#rlp-encoding" id="rlp-encoding"></a>

`0x80`

### AccountKeyLegacy <a href="#accountkeylegacy" id="accountkeylegacy"></a>

AccountKeyLegacy được dùng cho tài khoản có địa chỉ được lấy từ cặp khóa tương ứng. Nếu một tài khoản có AccountKeyLegacy, quy trình xác thực giao dịch sẽ được thực hiện như dưới đây (như một nền tảng chuỗi khối điển hình đã thực hiện):

* Lấy mã khóa công khai từ `ecrecover(txhash, txsig)`.
* Lấy địa chỉ của mã khóa công khai.
* Địa chỉ là người gửi.

#### Thuộc tính <a href="#attributes" id="attributes"></a>

| Thuộc tính | type       | Mô tả                                                |
| ---------- | ---------- | ---------------------------------------------------- |
| Type       | uint8 (Go) | Loại AccountKeyLegacy. Giá trị này phải là **0x01**. |

#### Mã hóa RLP <a href="#rlp-encoding" id="rlp-encoding"></a>

`0x01c0`

### AccountKeyPublic <a href="#accountkeypublic" id="accountkeypublic"></a>

AccountKeyPublic được dùng cho các tài khoản dùng một khóa công khai.\
Nếu tài khoản có một đối tượng AccountKeyPublic, thì quy trình xác thực giao dịch sẽ được thực hiện như bên dưới:

* Lấy mã khóa công khai từ `ecrecover(txhash, txsig)`.
* Kiểm tra đảm bảo mã khóa công khai lấy được giống với khóa tương ứng

  mã khóa công khai của tài khoản.

#### Thuộc tính <a href="#attributes" id="attributes"></a>

| Thuộc tính | type           | Mô tả                                                 |
| ---------- | -------------- | ----------------------------------------------------- |
| type       | uint8 (Go)     | Loại AccountKeyPublic. Giá trị này phải là **0x02**.  |
| Khóa       | \[33]byte (Go) | Khóa phải là khóa công khai được nén trên S256 curve. |

#### Mã hóa RLP <a href="#rlp-encoding" id="rlp-encoding"></a>

`0x02 + encode(CompressedPubKey)`

**LƯU Ý**: CompressedPubKey là mã khóa công khai ở định dạng nén được định nghĩa trong [SEC1](https://www.secg.org/SEC1-Ver-1.0.pdf). Tóm lại, dùng 0x02{PubkeyX} nếu PubkeyY là số chẵn, hoặc dùng 0x03{PubkeyX} trong trường hợp còn lại.

#### Mã hóa RLP (Ví dụ) <a href="#rlp-encoding-example" id="rlp-encoding-example"></a>

```javascript
prvkey 0xf8cc7c3813ad23817466b1802ee805ee417001fcce9376ab8728c92dd8ea0a6b
pubkeyX 0xdbac81e8486d68eac4e6ef9db617f7fbd79a04a3b323c982a09cdfc61f0ae0e8
pubkeyY 0x906d7170ba349c86879fb8006134cbf57bda9db9214a90b607b6b4ab57fc026e

RLP: 0x02a102dbac81e8486d68eac4e6ef9db617f7fbd79a04a3b323c982a09cdfc61f0ae0e8
```

### AccountKeyFail <a href="#accountkeyfail" id="accountkeyfail"></a>

Nếu tài khoản có khóa AccountKeyFail, thì quy trình xác thực giao dịch sẽ luôn thất bại. Khóa này có thể được sử dụng cho các tài khoản hợp đồng thông minh để một giao dịch được gửi từ một tài khoản hợp đồng thông minh luôn thất bại.

#### Thuộc tính <a href="#attributes" id="attributes"></a>

| Thuộc tính | type       | Mô tả                                              |
| ---------- | ---------- | -------------------------------------------------- |
| Loại      | uint8 (Go) | Loại AccountKeyFail. Giá trị này phải là **0x03**. |

#### Mã hóa RLP <a href="#rlp-encoding" id="rlp-encoding"></a>

`0x03c0`

### AccountKeyWeightedMultiSig <a href="#accountkeyweightedmultisig" id="accountkeyweightedmultisig"></a>

AccountKeyWeightedMultiSig là loại khóa tài khoản có chứa ngưỡng và WeightedPublicKeys có chứa một danh sách gồm một mã khóa công khai và trọng số của nó. Để một giao dịch được coi là hợp lệ cho một tài khoản liên kết với AccountKeyWeightedMultiSig, thì cần phải thỏa mã các điều kiện sau:

* Tổng trọng số của các mã khóa công khai đã ký phải lớn hơn ngưỡng.
* Giao dịch không được có chữ ký không hợp lệ.
* Số lượng mã khóa công khai đã ký phải ít hơn số lượng weightedPublicKey.

{% hint style="success" %}
LƯU Ý: Logic xác thực multiGig sau đây đã thay đổi với quá trình nâng cấp giao thức `IstanbulEVM`, hay còn gọi là "nâng cấp căn bản".

* Giao dịch không được có chữ ký không hợp lệ.
* Số lượng mã khóa công khai đã ký phải ít hơn số lượng weightedPublicKey. Nếu bạn muốn đọc tài liệu trước đây, vui lòng tham khảo phần [tài liệu trước đây](/content/klaytn/design/transaction-fees/transaction-fees-previous).

Số khối nâng cấp giao thức `IstanbulEVM` như sau.

* Mạng thử nghiệm Baobab: `#75373312`
* Mạng chính thức Cypress: `#86816005`
  {% endhint %}

#### Thuộc tính <a href="#attributes" id="attributes"></a>

| Thuộc tính         | Loại                     | Mô tả                                                                                                                           |
| ------------------ | ------------------------- | ------------------------------------------------------------------------------------------------------------------------------- |
| Loại              | uint8 (Go)                | Loại AccountKeyWeightedMultiSig. Giá trị này phải là **0x04**.                                                                  |
| Ngưỡng             | uint (Go)                 | Ngưỡng xác thực. Để được coi là giao dịch hợp lệ thì tổng trọng số của các chữ ký phải lớn hơn hoặc bằng ngưỡng này.            |
| WeightedPublicKeys | \[]{uint, \[33]byte} (Go) | Một danh sách khóa công khai có trọng số. Một khóa công khai có trọng số có chứa khóa công khai đã được nén và trọng số của nó. |

#### Mã hóa RLP <a href="#rlp-encoding" id="rlp-encoding"></a>

`0x04 + encode([threshold, [[weight, CompressedPubKey1], [weight2, CompressedPubKey2]]])`

#### Mã hóa RLP (Ví dụ) <a href="#rlp-encoding-example" id="rlp-encoding-example"></a>

```javascript
Threshold 3
Key0 Weight: 1
PubkeyX 0xc734b50ddb229be5e929fc4aa8080ae8240a802d23d3290e5e6156ce029b110e
PubkeyY 0x61a443ac3ffff164d1fb3617875f07641014cf17af6b7dc38e429fe838763712
Key1 Weight: 1
PubkeyX 0x12d45f1cc56fbd6cd8fc877ab63b5092ac77db907a8a42c41dad3e98d7c64dfb
PubkeyY 0x8ef355a8d524eb444eba507f236309ce08370debaa136cb91b2f445774bff842
Key2 Weight: 1
PubkeyX 0xea9a9f85065a00d7b9ffd3a8532a574035984587fd08107d8f4cbad6b786b0cd
PubkeyY 0xb95ebb02d9397b4a8faceb58d485d612f0379a923ec0ddcf083378460a56acca
Key3 Weight: 1
PubkeyX 0x8551bc489d62fa2e6f767ba87fe93a62b679fca8ff3114eb5805e6487b51e8f6
PubkeyY 0x4206aa84bc8955fcbfcc396854228aa63ebacd81b7311a31ab9d71d90b7ec3d7

RLP: 0x04f89303f890e301a102c734b50ddb229be5e929fc4aa8080ae8240a802d23d3290e5e6156ce029b110ee301a10212d45f1cc56fbd6cd8fc877ab63b5092ac77db907a8a42c41dad3e98d7c64dfbe301a102ea9a9f85065a00d7b9ffd3a8532a574035984587fd08107d8f4cbad6b786b0cde301a1038551bc489d62fa2e6f767ba87fe93a62b679fca8ff3114eb5805e6487b51e8f6
```

### AccountKeyRoleBased <a href="#accountkeyrolebased" id="accountkeyrolebased"></a>

AccountKeyRoleBased tương ứng với một khóa theo vai trò. Các vai trò được nêu rõ trong phần \[Các vai trò]\(tài khoảns.md#roles).

#### Thuộc tính <a href="#attributes" id="attributes"></a>

| Thuộc tính | Loại                | Mô tả                                                                                                                                                            |
| ---------- | -------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Loại      | uint8 (Go)           | Loại AccountKeyRoleBased. Giá trị này phải là **0x05**.                                                                                                          |
| Khóa       | \[]{AccountKey} (Go) | Một danh sách các khóa. Khóa có thể là bất kỳ khóa nào trong số AccountKeyNil, AccountKeyLegacy, AccountKeyPublic, AccountKeyFail và AccountKeyWeightedMultiSig. |

#### Vai trò <a href="#roles" id="roles"></a>

Các vai trò của AccountKeyRoleBased được định nghĩa bên dưới:

| Vai trò           | Mô tả                                                                                                                                                                                                                           |
| ----------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| RoleTransaction   | Chỉ mục 0. Khóa mặc định. Các giao dịch khác với TxTypeAccountUpdate cần được ký bởi khóa của vai trò này.                                                                                                                      |
| RoleAccountUpdate | Chỉ mục 1. Giao dịch TxTypeAccountUpdate phải được ký bởi khóa này. Nếu khóa này không hiển thị trong tài khoản, giao dịch TxTypeAccountUpdate là không hợp lệ khi dùng khóa RoleTransaction.                                   |
| RoleFeePayer      | Chỉ mục 2. Nếu tài khoản này muốn gửi phí tx thay cho người gửi, thì giao dịch phải được ký bởi khóa này. Nếu khóa này không hiển thị trong tài khoản, một giao dịch có phí ủy thác sẽ được xác thực bằng khóa RoleTransaction. |

#### Mã hóa RLP <a href="#rlp-encoding" id="rlp-encoding"></a>

`0x05 + encode([key1, key2, key3])`

Lưu ý rằng key1, key2 và key3 có thể là bất kỳ khóa nào trong số các khóa trên (AccountKeyNil, AccountKeyLegacy, AccountKeyPublic, AccountKeyFail và AccountKeyWeightedMultiSig).

#### Các vài trò có thể bỏ qua và có thể mở rộng <a href="#omissible-and-expandable-roles" id="omissible-and-expandable-roles"></a>

Các vai trò có thể được bỏ ra khỏi chỉ mục gần nhất và các vai trò đã bỏ qua được ánh xạ đến vai trò đầu tiên. Tuy nhiên, vai trò ở giữa thì không thể bỏ qua được, có nghĩa là không thể đặt RoleTransaction và RoleFeePayer khi không có RoleAccountUpdate. Ví dụ, nếu một khóa dựa trên vai trò được đặt là `0x05 + encode([key1, key2])`, thì RoleFeePayer sẽ có vai trò như thể khóa đó được đặt là `0x05 + encode([key1, key2, key1])`.

Tính năng này cho phép bạn thêm nhiều vai trò hơn trong tương lai. Nếu một vai trò mới được cung cấp, vai trò mới của các tài khoản đã được tạo cùng các vai trò cũ sẽ được ánh xạ đến vai trò đầu tiên.

#### Mã hóa RLP (Ví dụ) <a href="#rlp-encoding-example" id="rlp-encoding-example"></a>

```javascript
RoleTransaction Key
PubkeyX 0xe4a01407460c1c03ac0c82fd84f303a699b210c0b054f4aff72ff7dcdf01512d
PubkeyY 0x0a5735a23ce1654b14680054a993441eae7c261983a56f8e0da61280758b5919
RoleAccountUpdate Key
Threshold: 2
Key0 Weight:1
PubkeyX 0xe4a01407460c1c03ac0c82fd84f303a699b210c0b054f4aff72ff7dcdf01512d
PubkeyY 0x0a5735a23ce1654b14680054a993441eae7c261983a56f8e0da61280758b5919
Key1 Weight:1
PubkeyX 0x36f6355f5b532c3c1606f18fa2be7a16ae200c5159c8031dd25bfa389a4c9c06
PubkeyY 0x6fdf9fc87a16ac359e66d9761445d5ccbb417fb7757a3f5209d713824596a50d
RoleFeePayer Key
PubkeyX 0xc8785266510368d9372badd4c7f4a94b692e82ba74e0b5e26b34558b0f081447
PubkeyY 0x94c27901465af0a703859ab47f8ae17e54aaba453b7cde5a6a9e4a32d45d72b2

RLP: 0x05f898a302a103e4a01407460c1c03ac0c82fd84f303a699b210c0b054f4aff72ff7dcdf01512db84e04f84b02f848e301a103e4a01407460c1c03ac0c82fd84f303a699b210c0b054f4aff72ff7dcdf01512de301a10336f6355f5b532c3c1606f18fa2be7a16ae200c5159c8031dd25bfa389a4c9c06a302a102c8785266510368d9372badd4c7f4a94b692e82ba74e0b5e26b34558b0f081447
```

## Mã loại khóa tài khoản <a href="#account-key-type-id" id="account-key-type-id"></a>

Dưới đây là Mã loại khóa tài khoản được chỉ định cho từng Loại khóa tài khoản.

| Loại khóa tài khoản        | Mã loại khóa tài khoản |
| -------------------------- | ---------------------- |
| AccountKeyLegacy           | 0x01                   |
| AccountKeyPublic           | 0x02                   |
| AccountKeyFail             | 0x03                   |
| AccountKeyWeightedMultiSig | 0x04                   |
| AccountKeyRoleBased        | 0x05                   |


# Giao dịch

## Tổng quan về giao dịch <a href="#transactions-overview" id="transactions-overview"></a>

Một giao dịch trong nền tảng chuỗi khối là một thông điệp mà các nút gửi cho nhau, làm thay đổi trạng thái của chuỗi khối. Ví dụ: khi thực thi một giao dịch gửi 10 KLAY từ tài khoản của Alice đến tài khoản của Bob, số dư của Alice sẽ giảm 10 KLAY và số dư của Bob tăng 10 KLAY. Lưu ý rằng một giao dịch không thể xen kẽ với một giao dịch khác vì giao dịch là một hoạt động nguyên tử. Một giao dịch chuỗi khối điển hình có các thành phần như dưới đây:

| Thành phần | Mô tả                                                                                                                                                                                                                                                                                                                                                           |
| ---------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| giá trị    | Số lượng KLAY tính bằng `peb` sẽ được chuyển.                                                                                                                                                                                                                                                                                                                   |
| đến        | Địa chỉ tài khoản sẽ nhận giá trị được chuyển.                                                                                                                                                                                                                                                                                                                  |
| nhập       | Dữ liệu được gắn kèm giao dịch, dùng để thực thi giao dịch.                                                                                                                                                                                                                                                                                                     |
| v, r, s    | Chữ ký mật mã được tạo bởi người gửi để cho phép người nhận lấy được địa chỉ của người gửi.                                                                                                                                                                                                                                                                     |
| nonce      | Giá trị dùng để định danh duy nhất cho một giao dịch của người gửi. Nếu hai giao dịch có cùng một giá trị số dùng một lần do người gửi tạo ra, chỉ có một giao dịch sẽ được thực thi.                                                                                                                                                                           |
| gas        | Giá trị phí giao dịch tối đa mà giao dịch được phép sử dụng.                                                                                                                                                                                                                                                                                                    |
| giá gas    | Hệ số nhân để tính toán số lượng token mà người gửi sẽ thanh toán. Lượng token mà người gửi sẽ thanh toán được tính theo công thức `gas` \* `gasPrice`. Ví dụ: Người gửi sẽ thanh toán khoản phí giao dịch là 10 KLAY nếu gas bằng 10 và gasPrice là 10^18. Đơn vị của KLAY được mô tả [tại đây](/content/klaytn/design/klaytn-native-coin-klay#units-of-klay). |

## Các giao dịch của Klaytn <a href="#klaytn-transactions" id="klaytn-transactions"></a>

Khi các nền tảng chuỗi khối thông thường cung cấp một loại giao dịch duy nhất, Klaytn cung cấp nhiều loại giao dịch, thúc đẩy các giao dịch nhờ những khả năng mới và tối ưu hóa vùng phủ bộ nhớ và hiệu suất.

### Xác thực chữ ký của giao dịch <a href="#signature-validation-of-transactions" id="signature-validation-of-transactions"></a>

Trong các nền tảng chuỗi khối thông thường, địa chỉ được lấy khóa công khai, sau đó khóa này được lấy lại từ chữ ký giao dịch. Điều này chỉ có thể xảy ra nếu địa chỉ và cặp khóa được gắn chặt chẽ với nhau.

Vì trong Klaytn, một cặp khóa được tách khỏi địa chỉ, địa chỉ của người gửi không thể lấy được bằng cách sử dụng chữ ký giao dịch. Đây là lí do khiến các loại giao dịch của Klaytn, trừ TxTypeLegacyTransaction có trường `from`. Trong Klaytn, để xác thực một giao dịch, \[AccountKey]\(../tài khoảns.md#tài khoản-key) của `from` sẽ được lấy, và khóa lấy được sẽ dùng để xác thực chữ ký của giao dịch.

### Ủy thác phí <a href="#fee-delegation" id="fee-delegation"></a>

Để mang lại cho các doanh nghiệp sự linh hoạt cần thiết trong thiết kế mô hình kinh doanh của họ, Klaytn cung cấp một số phiên bản ủy thác phí dành cho các loại giao dịch cơ bản. Những biến số này cho phép các nhà cung cấp dịch vụ trợ cấp cho các hoạt động của người dùng cuối bằng cách thanh toán phí giao dịch cho người dùng. Việc trợ cấp phí giao dịch có thể được diễn giải chi tiết hơn bằng cách sử dụng các giao dịch có tham số Tỷ lệ, cho phép các nhà cung cấp dịch vụ chỉ định tỷ lệ phần trăm phí mà họ sẽ chi trả. Các giao dịch ủy thác phí cần ít nhất hai chữ ký: một chữ ký từ người gửi và một chữ ký từ người trả phí.

### SenderTxHash <a href="#sendertxhash" id="sendertxhash"></a>

SenderTxHash là hàm băm của một giao dịch không chứa địa chỉ và chữ ký của người trả phí. Hàm băm giao dịch của một giao dịch có phí ủy thác chưa được xác định cho đến khi người trả phí ký giao dịch. Để theo dõi một giao dịch có phí ủy thác, người gửi phải gửi hàm băm giao dịch lấy từ giao dịch hoàn thiện, trong đó có chứa các chữ ký từ cả người gửi và người trả phí. Bởi vì người gửi rất khó lấy được hàm băm giao dịch, Klaytn cung cấp SenderTxHash và hàm băm giao dịch. Để tìm giao dịch có phí ủy thác hoàn thiện trong mạng lưới Klaytn, người gửi tạo một SenderTxHash và yêu cầu một đối tượng giao dịch qua [klay\_getTransactionBySenderTxHash](https://github.com/klaytn/klaytn-docs-vn/blob/main/docs/bapp/json-rpc/api-references/klay/transaction.md#klay_gettransactionbysendertxhash). Cách để lấy SenderTxHash tùy thuộc vào từng loại giao dịch, thông tin có trong phần mô tả của từng loại giao dịch.

Từng loại giao dịch được mô tả chi tiết:

|                        | Cơ bản                                                                                                 | Ủy thác phí                                                                                                                             | Ủy thác phí một phần                                                                                                                                              |
| ---------------------- | ------------------------------------------------------------------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Legacy                 | [TxTypeLegacyTransaction](/content/klaytn/design/transactions/basic#txtypelegacytransaction)           | Không có                                                                                                                                | Không có                                                                                                                                                          |
| ValueTransfer          | [TxTypeValueTransfer](/content/klaytn/design/transactions/basic#txtypevaluetransfer)                   | [TxTypeFeeDelegatedValueTransfer](/content/klaytn/design/transactions/fee-delegation#txtypefeedelegatedvaluetransfer)                   | [TxTypeFeeDelegatedValueTransferWithRatio](/content/klaytn/design/transactions/partial-fee-delegation#txtypefeedelegatedvaluetransferwithratio)                   |
| ValueTransferMemo      | [TxTypeValueTransferMemo](/content/klaytn/design/transactions/basic#txtypevaluetransfermemo)           | [TxTypeFeeDelegatedValueTransferMemo](/content/klaytn/design/transactions/fee-delegation#txtypefeedelegatedvaluetransfermemo)           | [TxTypeFeeDelegatedValueTransferMemoWithRatio](/content/klaytn/design/transactions/partial-fee-delegation#txtypefeedelegatedvaluetransfermemowithratio)           |
| SmartContractDeploy    | [TxTypeSmartContractDeploy](/content/klaytn/design/transactions/basic#txtypesmartcontractdeploy)       | [TxTypeFeeDelegatedSmartContractDeploy](/content/klaytn/design/transactions/fee-delegation#txtypefeedelegatedsmartcontractdeploy)       | [TxTypeFeeDelegatedSmartContractDeployWithRatio](/content/klaytn/design/transactions/partial-fee-delegation#txtypefeedelegatedsmartcontractdeploywithratio)       |
| SmartContractExecution | [TxTypeSmartContractExecution](/content/klaytn/design/transactions/basic#txtypesmartcontractexecution) | [TxTypeFeeDelegatedSmartContractExecution](/content/klaytn/design/transactions/fee-delegation#txtypefeedelegatedsmartcontractexecution) | [TxTypeFeeDelegatedSmartContractExecutionWithRatio](/content/klaytn/design/transactions/partial-fee-delegation#txtypefeedelegatedsmartcontractexecutionwithratio) |
| AccountUpdate          | [TxTypeAccountUpdate](/content/klaytn/design/transactions/basic#txtypeaccountupdate)                   | [TxTypeFeeDelegatedAccountUpdate](/content/klaytn/design/transactions/fee-delegation#txtypefeedelegatedaccountupdate)                   | [TxTypeFeeDelegatedAccountUpdateWithRatio](/content/klaytn/design/transactions/partial-fee-delegation#txtypefeedelegatedaccountupdatewithratio)                   |
| Cancel                 | [TxTypeCancel](/content/klaytn/design/transactions/basic#txtypecancel)                                 | [TxTypeFeeDelegatedCancel](/content/klaytn/design/transactions/fee-delegation#txtypefeedelegatedcancel)                                 | [TxTypeFeeDelegatedCancelWithRatio](/content/klaytn/design/transactions/partial-fee-delegation#txtypefeedelegatedcancelwithratio)                                 |
| ChainDataAnchoring     | [TxTypeChainDataAnchoring](/content/klaytn/design/transactions/basic#txtypechaindataanchoring)         | [TxTypeFeeDelegatedChainDataAnchoring](/content/klaytn/design/transactions/fee-delegation#txtypefeedelegatedchaindataanchoring)         | [TxTypeFeeDelegatedChainDataAnchoringWithRatio](/content/klaytn/design/transactions/partial-fee-delegation#txtypefeedelegatedchaindataanchoringwithratio)         |


# Cơ bản

## TxTypeLegacyTransaction <a href="#txtypelegacytransaction" id="txtypelegacytransaction"></a>

TxTypeLegacyTransaction đại diện cho một loại giao dịch đã tồn tại trước đây trong Klaytn. Loại giao dịch này tồn tại để hỗ trợ khả năng tương thích nên chỉ hoạt động với các EOA liên kết với \[AccountKeyLegacy]\[]. Các EOA liên kết với loại khóa tài khoản khác sẽ sử dụng những loại giao dịch khác như TxTypeValueTransfer, TxTypeSmartContractExecution, v.v. Loại giao dịch này có thể tạo một tài khoản, chuyển token, triển khai một hợp đồng thông minh, thực thi một hợp đồng thông minh hoặc kết hợp các hoạt động vừa nêu. Loại giao dịch này sẽ khởi tạo các thay đổi sau.

1. Số dư của người gửi giảm đi một lượng bằng khoản phí giao dịch.
2. Số dùng một lần của người gửi tăng thêm một đơn vị.
3. Nếu `to` không tồn tại trên Klaytn, một EOA liên kết với \[AccountKeyLegacy]\[] sẽ được tạo ra.
4. `value` KLAY sẽ được chuyển từ người gửi đến người nhận.
5. Nếu `to` chưa có giá trị, nó sẽ được coi là một giao dịch triển khai hợp đồng thông minh. Mã hợp đồng thông minh phải được dùng dưới dạng `input`.
6. Nếu `to` là một hợp đồng thông minh, hàm hợp đồng thông minh được chỉ định trong `input` sẽ được thực thi.

### Thuộc tính <a href="#attributes" id="attributes"></a>

| Thuộc tính | type                  | Mô tả                                                                                                                                                                                                                                                                                                                                                |
| ---------- | --------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| giá trị    | \*big.Int (Go)        | Số lượng KLAY tính bằng `peb` sẽ được chuyển.                                                                                                                                                                                                                                                                                                        |
| đến        | \*common.Address (Go) | Địa chỉ tài khoản sẽ nhận giá trị được chuyển.                                                                                                                                                                                                                                                                                                       |
| nhập       | \[]byte (Go)          | Dữ liệu được gắn kèm giao dịch, dùng để thực thi giao dịch.                                                                                                                                                                                                                                                                                          |
| v, r, s    | \*big.Int (Go)        | Chữ ký mật mã được tạo bởi người gửi để cho phép người nhận lấy được địa chỉ của người gửi.                                                                                                                                                                                                                                                          |
| nonce      | uint64 (Go)           | Giá trị dùng để định danh duy nhất cho một giao dịch của người gửi. Nếu hai giao dịch có cùng một giá trị số dùng một lần do người gửi tạo ra, chỉ có một giao dịch sẽ được thực thi.                                                                                                                                                                |
| gas        | uint64 (Go)           | Giá trị phí giao dịch tối đa mà giao dịch được phép sử dụng.                                                                                                                                                                                                                                                                                         |
| giá gas    | \*big.Int (Go)        | Hệ số nhân để tính toán số lượng token mà người gửi sẽ thanh toán. Lượng token mà người gửi sẽ thanh toán được tính theo công thức `gas` \* `gasPrice`. Ví dụ: Người gửi sẽ thanh toán khoản phí giao dịch là 10 KLAY nếu gas bằng 10 và gasPrice là 10^18. Hãy xem [Đơn vị của KLAY](/content/klaytn/design/klaytn-native-coin-klay#units-of-klay). |

### Mã hóa RLP cho chữ ký <a href="#rlp-encoding-for-signature" id="rlp-encoding-for-signature"></a>

Để tạo chữ ký của loại giao dịch này, quá trình tuần tự hóa RLP phải diễn ra như sau:

```javascript
SigRLP = encode([nonce, gasPrice, gas, to, value, input, chainid, 0, 0])
SigHash = keccak256(SigRLP)
Signature = sign(SigHash, <private key>)
```

### Mã hóa RLP cho SenderTxHash <a href="#rlp-encoding-for-sendertxhash" id="rlp-encoding-for-sendertxhash"></a>

Để tạo một SenderTxHash, quá trình tuần tự hóa RLP phải diễn ra như sau:

```javascript
SenderTxHashRLP = encode([nonce, gasPrice, gas, to, value, input, v, r, s])
SenderTxHash = keccak256(SenderTxHashRLP)
```

### Mã hóa RLP cho hàm băm giao dịch <a href="#rlp-encoding-for-transaction-hash" id="rlp-encoding-for-transaction-hash"></a>

Để tạo một hàm băm giao dịch, quá trình tuần tự hóa RLP phải diễn ra như sau:

```javascript
TxHashRLP = encode([nonce, gasPrice, gas, to, value, input, v, r, s])
TxHash = keccak256(TxHashRLP)
```

### Mã hóa RLP (Ví dụ) <a href="#rlp-encoding-example" id="rlp-encoding-example"></a>

Phần dưới đây cho thấy kết quả của quá trình tuần tự hóa RLP và đối tượng giao dịch:

```javascript
ChainID 0x1
PrivateKey 0x45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8
PublicKey.X 0x3a514176466fa815ed481ffad09110a2d344f6c9b78c1d14afc351c3a51be33d
PublicKey.Y 0x8072e77939dc03ba44790779b7a1025baf3003f6732430e20cd9b76d953391b3
SigRLP 0xe68204d219830f4240947b65b75d204abed71587c9e519a89277766ee1d00a8431323334018080
SigHash 0x40e73366650cddb7affcf5af39efa864b2c68c42b5329044fc86a12b26c4edc7
Signature f845f84325a0b2a5a15550ec298dc7dddde3774429ed75f864c82caeb5ee24399649ad731be9a029da1014d16f2011b3307f7bbe1035b6e699a4204fc416c763def6cefd976567
TxHashRLP 0xf8668204d219830f4240947b65b75d204abed71587c9e519a89277766ee1d00a843132333425a0b2a5a15550ec298dc7dddde3774429ed75f864c82caeb5ee24399649ad731be9a029da1014d16f2011b3307f7bbe1035b6e699a4204fc416c763def6cefd976567
TxHash e434257753bf31a130c839fec0bd34fc6ea4aa256b825288ee82db31c2ed7524
SenderTxHashRLP 0xf8668204d219830f4240947b65b75d204abed71587c9e519a89277766ee1d00a843132333425a0b2a5a15550ec298dc7dddde3774429ed75f864c82caeb5ee24399649ad731be9a029da1014d16f2011b3307f7bbe1035b6e699a4204fc416c763def6cefd976567
SenderTxHash e434257753bf31a130c839fec0bd34fc6ea4aa256b825288ee82db31c2ed7524

    TX(e434257753bf31a130c839fec0bd34fc6ea4aa256b825288ee82db31c2ed7524)
    Contract: false
    From:     a94f5374fce5edbc8e2a8697c15331677e6ebf0b
    To:       7b65b75d204abed71587c9e519a89277766ee1d0
    Nonce:    1234
    GasPrice: 0x19
    GasLimit  0xf4240
    Value:    0xa
    Data:     0x31323334
    V:        0x25
    R:        0xb2a5a15550ec298dc7dddde3774429ed75f864c82caeb5ee24399649ad731be9
    S:        0x29da1014d16f2011b3307f7bbe1035b6e699a4204fc416c763def6cefd976567
    Hex:      f8668204d219830f4240947b65b75d204abed71587c9e519a89277766ee1d00a843132333425a0b2a5a15550ec298dc7dddde3774429ed75f864c82caeb5ee24399649ad731be9a029da1014d16f2011b3307f7bbe1035b6e699a4204fc416c763def6cefd976567
```

### Kết quả đầu ra RPC (Example) <a href="#rpc-output-example" id="rpc-output-example"></a>

Phần dưới đây cho thấy một đối tượng giao dịch được trả về qua JSON RPC.

```javascript
{
  "blockHash": "0xeff95d8c57d668aa274a0eaeff942ecc2cfca4c71f71ae9fdaba92735cd79b9e",
  "blockNumber": "0x1",
  "contractAddress": null,
  "from": "0x33c97827c33d8c5e07eb263ed6ec5c229e8b4752",
  "gas": "0x174876e800",
  "gasPrice": "0x5d21dba00",
  "gasUsed": "0x5208",
  "input": "0x",
  "nhật ký": [],
  "nhật kýBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
  "nonce": "0x0",
  "senderTxHash": "0xff0e9a45aa8741d528baf84069cd3b52c43a51bf7cf69d896672c3c909507888",
  "signatures": [
    {
      "V": "0x25",
      "R": "0xed8aa552324101a99792860d479cd488b7f67af0b9205968748bddcda52da6de",
      "S": "0x524dbf481ea1d77c20f4d4354cc208c3149ddfa06f7ab53a03ad82d2d7fed3"
    }
  ],
  "trạng thái": "0x1",
  "to": "0xd03227635c90c7986f0e3a4e551cefbca8c55316",
  "transactionHash": "0xff0e9a45aa8741d528baf84069cd3b52c43a51bf7cf69d896672c3c909507888",
  "transactionIndex": "0x0",
  "type": "TxTypeLegacyTransaction",
  "typeInt": 0,
  "value": "0x174876e800"
}
```

## TxTypeValueTransfer <a href="#txtypevaluetransfer" id="txtypevaluetransfer"></a>

TxTypeValueTransfer được sử dụng khi người dùng muốn gửi KLAY. Vì Klaytn cung cấp nhiều loại giao dịch để mỗi loại giao dịch chỉ phục vụ một mục đích duy nhất, TxTypeValueTransfer bị giới hạn chỉ gửi KLAY đến một tài khoản sở hữu bên ngoài. Vì thế, TxTypeValueTransfer chỉ được chấp nhận nếu `to` là một tài khoản sở hữu bên ngoài. Để chuyển KLAY đến một tài khoản hợp đồng thông minh, hãy dùng [TxTypeSmartContractExecution](#txtypesmartcontractexecution). Các thay đổi sau sẽ được tạo ra nhờ loại giao dịch này.

1. Số dư của người gửi giảm đi một lượng bằng khoản phí giao dịch.
2. Số dùng một lần của người gửi tăng thêm một đơn vị.
3. `value` KLAY sẽ được chuyển từ người gửi đến người nhận.

### Thuộc tính <a href="#attributes" id="attributes"></a>

| Thuộc tính   | Loại                                     | Mô tả                                                                                                                                                                                                                                                                                                                                    |
| ------------ | ----------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| type         | uint8 (Go)                                | Loại TxTypeValueTransfer. Thuộc tính này phải là 0x08.                                                                                                                                                                                                                                                                                   |
| nonce        | uint64 (Go)                               | Giá trị dùng để định danh duy nhất cho một giao dịch của người gửi. Nếu hai giao dịch có cùng một giá trị số dùng một lần do người gửi tạo ra, chỉ có một giao dịch sẽ được thực thi.                                                                                                                                                    |
| giá gas      | \*big.Int (Go)                            | Đơn giá của gas tính bằng `peb` mà người gửi sẽ dùng để thanh toán phí giao dịch. Số tiền phí giao dịch được tính theo công thức `gas` \* `gasPrice`. Ví dụ: nếu giao dịch tốn 10 đơn vị gas và gasPrice là 10^18, phí giao dịch sẽ là 10 KLAY. Hãy xem [Đơn vị của KLAY](/content/klaytn/design/klaytn-native-coin-klay#units-of-klay). |
| gas          | uint64 (Go)                               | Lượng gas tối đa mà giao dịch được phép sử dụng.                                                                                                                                                                                                                                                                                         |
| đến          | common.Address (Go)                       | Địa chỉ tài khoản sẽ nhận giá trị được chuyển.                                                                                                                                                                                                                                                                                           |
| giá trị      | \*big.Int (Go)                            | Số lượng KLAY tính bằng `peb` sẽ được chuyển.                                                                                                                                                                                                                                                                                            |
| từ           | common.Address (Go)                       | Địa chỉ của người gửi. Để biết thêm chi tiết, hãy xem [Xác thực chữ ký của giao dịch](/content/klaytn/design/transactions#signature-validation-of-transactions).                                                                                                                                                                         |
| txSignatures | \[]{\*big.Int, \*big.Int, \*big.Int} (Go) | Chữ ký của người gửi. Để biết thêm chi tiết, hãy xem [Xác thực chữ ký của giao dịch](/content/klaytn/design/transactions#signature-validation-of-transactions).                                                                                                                                                                          |

### Mã hóa RLP cho chữ ký <a href="#rlp-encoding-for-signature" id="rlp-encoding-for-signature"></a>

Để tạo một chữ ký giao dịch, quá trình tuần tự hóa RLP phải diễn ra như sau:

```javascript
SigRLP = encode([encode([type, nonce, gasPrice, gas, to, value, from]), chainid, 0, 0])
SigHash = keccak256(SigRLP)
Signature = sign(SigHash, <private key>)
```

### Mã hóa RLP cho SenderTxHash <a href="#rlp-encoding-for-sendertxhash" id="rlp-encoding-for-sendertxhash"></a>

Để tạo một SenderTxHash, quá trình tuần tự hóa RLP phải diễn ra như sau:

```javascript
txSignatures (a single signature) = [[v, r, s]]
txSignatures (two signatures) = [[v1, r1, s1], [v2, r2, s2]]
SenderTxHashRLP = type + encode([nonce, gasPrice, gas, to, value, from, txSignatures])
SenderTxHash = keccak256(SenderTxHashRLP)
```

### Mã hóa RLP cho hàm băm giao dịch <a href="#rlp-encoding-for-transaction-hash" id="rlp-encoding-for-transaction-hash"></a>

Để tạo một hàm băm giao dịch, quá trình tuần tự hóa RLP phải diễn ra như sau:

```javascript
txSignatures (a single signature) = [[v, r, s]]
txSignatures (two signatures) = [[v1, r1, s1], [v2, r2, s2]]
TxHashRLP = type + encode([nonce, gasPrice, gas, to, value, from, txSignatures])
TxHash = keccak256(TxHashRLP)
```

### Mã hóa RLP (Ví dụ) <a href="#rlp-encoding-example" id="rlp-encoding-example"></a>

Phần dưới đây cho thấy kết quả của quá trình tuần tự hóa RLP với các tham số cho trước và thông tin của đối tượng giao dịch:

```javascript
ChainID 0x1
PrivateKey 0x45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8
PublicKey.X 0x3a514176466fa815ed481ffad09110a2d344f6c9b78c1d14afc351c3a51be33d
PublicKey.Y 0x8072e77939dc03ba44790779b7a1025baf3003f6732430e20cd9b76d953391b3
SigRLP 0xf839b5f4088204d219830f4240947b65b75d204abed71587c9e519a89277766ee1d00a94a94f5374fce5edbc8e2a8697c15331677e6ebf0b018080
SigHash 0xaa7665566c9508140bb91e36a948fc8f61c4518400a69562432d17e064f3ce43
Signature f845f84325a0f3d0cd43661cabf53425535817c5058c27781f478cb5459874feaa462ed3a29aa06748abe186269ff10b8100a4b7d7fea274b53ea2905acbf498dc8b5ab1bf4fbc
TxHashRLP 0x08f87a8204d219830f4240947b65b75d204abed71587c9e519a89277766ee1d00a94a94f5374fce5edbc8e2a8697c15331677e6ebf0bf845f84325a0f3d0cd43661cabf53425535817c5058c27781f478cb5459874feaa462ed3a29aa06748abe186269ff10b8100a4b7d7fea274b53ea2905acbf498dc8b5ab1bf4fbc
TxHash 762f130342569e9669a4d8547f1248bd2554fbbf3062d63a97ce28bfa97aa9d7
SenderTxHashRLP 0x08f87a8204d219830f4240947b65b75d204abed71587c9e519a89277766ee1d00a94a94f5374fce5edbc8e2a8697c15331677e6ebf0bf845f84325a0f3d0cd43661cabf53425535817c5058c27781f478cb5459874feaa462ed3a29aa06748abe186269ff10b8100a4b7d7fea274b53ea2905acbf498dc8b5ab1bf4fbc
SenderTxHash 762f130342569e9669a4d8547f1248bd2554fbbf3062d63a97ce28bfa97aa9d7

    TX(762f130342569e9669a4d8547f1248bd2554fbbf3062d63a97ce28bfa97aa9d7)
    Type:          TxTypeValueTransfer
    From:          0xa94f5374Fce5edBC8E2a8697C15331677e6EbF0B
    To:            0x7b65B75d204aBed71587c9E519a89277766EE1d0
    Nonce:         1234
    GasPrice:      0x19
    GasLimit:      0xf4240
    Value:         0xa
    Signature:     [{"V":"0x25","R":"0xf3d0cd43661cabf53425535817c5058c27781f478cb5459874feaa462ed3a29a","S":"0x6748abe186269ff10b8100a4b7d7fea274b53ea2905acbf498dc8b5ab1bf4fbc"}]
    Hex:           08f87a8204d219830f4240947b65b75d204abed71587c9e519a89277766ee1d00a94a94f5374fce5edbc8e2a8697c15331677e6ebf0bf845f84325a0f3d0cd43661cabf53425535817c5058c27781f478cb5459874feaa462ed3a29aa06748abe186269ff10b8100a4b7d7fea274b53ea2905acbf498dc8b5ab1bf4fbc
```

### Kết quả đầu ra RPC (Example) <a href="#rpc-output-example" id="rpc-output-example"></a>

Phần dưới đây cho thấy một đối tượng giao dịch được trả về qua JSON RPC.

```javascript
{
  "blockHash": "0xeff95d8c57d668aa274a0eaeff942ecc2cfca4c71f71ae9fdaba92735cd79b9e",
  "blockNumber": "0x1",
  "contractAddress": null,
  "from": "0x33c97827c33d8c5e07eb263ed6ec5c229e8b4752",
  "gas": "0x174876e800",
  "gasPrice": "0x5d21dba00",
  "gasUsed": "0x5208",
  "nhật ký": [],
  "nhật kýBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
  "nonce": "0x1",
  "senderTxHash": "0x8c18c9a609d2b22c921ce0b282e64924bf073e84f7c3850d99ec71da4054f79d",
  "signatures": [
    {
      "V": "0x25",
      "R": "0x94e059980bce9f3ba5f09e5021ad4f32d7d9cfda938c2d38c989cd4a406e7ba",
      "S": "0x3ca52ee9d23954a278e6a30f3ec40951b26fb8b3f784c236c5bb1d5c9a8b2c82"
    }
  ],
  "trạng thái": "0x1",
  "to": "0x75c3098be5e4b63fbac05838daaee378dd48098d",
  "transactionHash": "0x8c18c9a609d2b22c921ce0b282e64924bf073e84f7c3850d99ec71da4054f79d",
  "transactionIndex": "0x1",
  "type": "TxTypeValueTransfer",
  "typeInt": 8,
  "value": "0x21e19e0c9bab2400000"
}
```

## TxTypeValueTransferMemo <a href="#txtypevaluetransfermemo" id="txtypevaluetransfermemo"></a>

TxTypeValueTransferMemo được sử dụng khi người dùng muốn gửi KLAY với một tin nhắn cụ thể. TxTypeValueTransferMemo chỉ được chấp nhận nếu `to` là một tài khoản thuộc sở hữu bên ngoài. Để chuyển KLAY đến một tài khoản hợp đồng thông minh, hãy dùng [TxTypeSmartContractExecution](#txtypesmartcontractexecution). Các thay đổi sau sẽ được tạo ra nhờ loại giao dịch này.

1. Số dư của người gửi giảm đi một lượng bằng khoản phí giao dịch.
2. Số dùng một lần của người gửi tăng thêm một đơn vị.
3. `value` KLAY sẽ được chuyển từ người gửi đến người nhận.

### Thuộc tính <a href="#attributes" id="attributes"></a>

| Thuộc tính   | type                                      | Mô tả                                                                                                                                                                                                                                                                                                                                    |
| ------------ | ----------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| type         | uint8 (Go)                                | Loại TxTypeValueTransferMemo. Thuộc tính này phải là 0x10.                                                                                                                                                                                                                                                                               |
| nonce        | uint64 (Go)                               | Giá trị dùng để định danh duy nhất cho một giao dịch của người gửi. Nếu hai giao dịch có cùng một giá trị số dùng một lần do người gửi tạo ra, chỉ có một giao dịch sẽ được thực thi.                                                                                                                                                    |
| giá gas      | \*big.Int (Go)                            | Đơn giá của gas tính bằng `peb` mà người gửi sẽ dùng để thanh toán phí giao dịch. Số tiền phí giao dịch được tính theo công thức `gas` \* `gasPrice`. Ví dụ: nếu giao dịch tốn 10 đơn vị gas và gasPrice là 10^18, phí giao dịch sẽ là 10 KLAY. Hãy xem [Đơn vị của KLAY](/content/klaytn/design/klaytn-native-coin-klay#units-of-klay). |
| gas          | uint64 (Go)                               | Lượng gas tối đa mà giao dịch được phép sử dụng.                                                                                                                                                                                                                                                                                         |
| đến          | common.Address (Go)                       | Địa chỉ tài khoản sẽ nhận giá trị được chuyển.                                                                                                                                                                                                                                                                                           |
| giá trị      | \*big.Int (Go)                            | Số lượng KLAY tính bằng `peb` sẽ được chuyển.                                                                                                                                                                                                                                                                                            |
| từ           | common.Address (Go)                       | Địa chỉ của người gửi. Để biết thêm chi tiết, hãy xem [Xác thực chữ ký của giao dịch](/content/klaytn/design/transactions#signature-validation-of-transactions).                                                                                                                                                                         |
| nhập         | \[]byte (Go)                              | Dữ liệu gắn kèm theo giao dịch. Thông điệp cần được truyền vào thuộc tính này.                                                                                                                                                                                                                                                           |
| txSignatures | \[]{\*big.Int, \*big.Int, \*big.Int} (Go) | Chữ ký của người gửi. Để biết thêm chi tiết, hãy xem [Xác thực chữ ký của giao dịch](/content/klaytn/design/transactions#signature-validation-of-transactions).                                                                                                                                                                          |

### Mã hóa RLP cho chữ ký <a href="#rlp-encoding-for-signature" id="rlp-encoding-for-signature"></a>

Để tạo một chữ ký giao dịch, quá trình tuần tự hóa RLP phải diễn ra như sau:

```javascript
SigRLP = encode([encode([type, nonce, gasPrice, gas, to, value, from, input]), chainid, 0, 0])
SigHash = keccak256(SigRLP)
Signature = sign(SigHash, <private key>)
```

### Mã hóa RLP cho SenderTxHash <a href="#rlp-encoding-for-sendertxhash" id="rlp-encoding-for-sendertxhash"></a>

Để tạo một SenderTxHash, quá trình tuần tự hóa RLP phải diễn ra như sau:

```javascript
txSignatures (a single signature) = [[v, r, s]]
txSignatures (two signatures) = [[v1, r1, s1], [v2, r2, s2]]
SenderTxHashRLP = type + encode([nonce, gasPrice, gas, to, value, from, input, txSignatures])
SenderTxHash = keccak256(SenderTxHashRLP)
```

### Mã hóa RLP cho hàm băm giao dịch <a href="#rlp-encoding-for-transaction-hash" id="rlp-encoding-for-transaction-hash"></a>

Để tạo một hàm băm giao dịch, quá trình tuần tự hóa RLP phải diễn ra như sau:

```javascript
txSignatures (a single signature) = [[v, r, s]]
txSignatures (two signatures) = [[v1, r1, s1], [v2, r2, s2]]
TxHashRLP = type + encode([nonce, gasPrice, gas, to, value, from, input, txSignatures])
TxHash = keccak256(TxHashRLP)
```

### Mã hóa RLP (Ví dụ) <a href="#rlp-encoding-example" id="rlp-encoding-example"></a>

Phần dưới đây cho thấy kết quả của quá trình tuần tự hóa RLP và đối tượng giao dịch:

```javascript
ChainID 0x1
PrivateKey 0x45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8
PublicKey.X 0x3a514176466fa815ed481ffad09110a2d344f6c9b78c1d14afc351c3a51be33d
PublicKey.Y 0x8072e77939dc03ba44790779b7a1025baf3003f6732430e20cd9b76d953391b3
SigRLP 0xf841b83cf83a108204d219830f4240947b65b75d204abed71587c9e519a89277766ee1d00a94a94f5374fce5edbc8e2a8697c15331677e6ebf0b8568656c6c6f018080
SigHash 0x23dd6ca2c023a152cad636ac8ed0a1a7962d3eb4cb7f3c50e34c0cc42e37d48a
Signature f845f84325a07d2b0c89ee8afa502b3186413983bfe9a31c5776f4f820210cffe44a7d568d1ca02b1cbd587c73b0f54969f6b76ef2fd95cea0c1bb79256a75df9da696278509f3
TxHashRLP 0x10f8808204d219830f4240947b65b75d204abed71587c9e519a89277766ee1d00a94a94f5374fce5edbc8e2a8697c15331677e6ebf0b8568656c6c6ff845f84325a07d2b0c89ee8afa502b3186413983bfe9a31c5776f4f820210cffe44a7d568d1ca02b1cbd587c73b0f54969f6b76ef2fd95cea0c1bb79256a75df9da696278509f3
TxHash 6c7ee543c24e5b928b638a9f4502c1eca69103f5467ed4b6a2ed0ea5aede2e6b
SenderTxHashRLP 0x10f8808204d219830f4240947b65b75d204abed71587c9e519a89277766ee1d00a94a94f5374fce5edbc8e2a8697c15331677e6ebf0b8568656c6c6ff845f84325a07d2b0c89ee8afa502b3186413983bfe9a31c5776f4f820210cffe44a7d568d1ca02b1cbd587c73b0f54969f6b76ef2fd95cea0c1bb79256a75df9da696278509f3
SenderTxHash 6c7ee543c24e5b928b638a9f4502c1eca69103f5467ed4b6a2ed0ea5aede2e6b

    TX(6c7ee543c24e5b928b638a9f4502c1eca69103f5467ed4b6a2ed0ea5aede2e6b)
    Type:          TxTypeValueTransferMemo
    From:          0xa94f5374Fce5edBC8E2a8697C15331677e6EbF0B
    To:            0x7b65B75d204aBed71587c9E519a89277766EE1d0
    Nonce:         1234
    GasPrice:      0x19
    GasLimit:      0xf4240
    Value:         0xa
    Signature:     [{"V":"0x25","R":"0x7d2b0c89ee8afa502b3186413983bfe9a31c5776f4f820210cffe44a7d568d1c","S":"0x2b1cbd587c73b0f54969f6b76ef2fd95cea0c1bb79256a75df9da696278509f3"}]
    Data:          36383635366336633666
    Hex:           10f8808204d219830f4240947b65b75d204abed71587c9e519a89277766ee1d00a94a94f5374fce5edbc8e2a8697c15331677e6ebf0b8568656c6c6ff845f84325a07d2b0c89ee8afa502b3186413983bfe9a31c5776f4f820210cffe44a7d568d1ca02b1cbd587c73b0f54969f6b76ef2fd95cea0c1bb79256a75df9da696278509f3
```

### Kết quả đầu ra RPC (Example) <a href="#rpc-output-example" id="rpc-output-example"></a>

Phần dưới đây cho thấy một đối tượng giao dịch được trả về qua JSON RPC.

```javascript
{
  "blockHash": "0x7ad6ed1f9955be00db8fb5452125f0e9a3c0856abb5b4cc4aed91ffc134321da",
  "blockNumber": "0x1",
  "contractAddress": null,
  "from": "0x0fcda0f2efbe1b4e61b487701ce4f2f8abc3723d",
  "gas": "0x174876e800",
  "gasPrice": "0x5d21dba00",
  "gasUsed": "0x53fc",
  "input": "0x68656c6c6f",
  "nhật ký": [],
  "nhật kýBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
  "nonce": "0x4",
  "senderTxHash": "0x7311ef305064f2a6997c16cc8b5fc3fdf301549e7b7d0baa3a995a8e79479e5e",
  "signatures": [
    {
      "V": "0x25",
      "R": "0xd63673e1be7919e7ca42de64931c853fc568557b151e9b335df94b22de3a600f",
      "S": "0x57bc916a50856b4d197f6856f16370f72f3bb0ac411b1da793fdb5bb7066966f"
    }
  ],
  "trạng thái": "0x1",
  "to": "0x75c3098be5e4b63fbac05838daaee378dd48098d",
  "transactionHash": "0x7311ef305064f2a6997c16cc8b5fc3fdf301549e7b7d0baa3a995a8e79479e5e",
  "transactionIndex": "0x4",
  "type": "TxTypeValueTransferMemo",
  "typeInt": 16,
  "value": "0x989680"
}
```

## TxTypeSmartContractDeploy <a href="#txtypesmartcontractdeploy" id="txtypesmartcontractdeploy"></a>

TxTypeSmartContractDeploy triển khai hợp đồng thông minh đến địa chỉ đã cho. Các thay đổi sau sẽ được tạo ra nhờ loại giao dịch này.

1. Số dư của người gửi giảm đi một lượng bằng khoản phí giao dịch.
2. Số dùng một lần của người gửi tăng thêm một đơn vị.
3. Một hợp đồng thông minh được triển khai bằng mã trong `input`. Địa chỉ đã triển khai sẽ được trả về qua `contractAddress` trong biên lai.
4. `value` KLAY sẽ được chuyển từ người gửi đến người nhận.

### Thuộc tính <a href="#attributes" id="attributes"></a>

| Thuộc tính    | Loại                                     | Mô tả                                                                                                                                                                                                                                                                                                                                    |
| ------------- | ----------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| type          | uint8 (Go)                                | Loại TxTypeSmartContractDeploy. Thuộc tính này phải là 0x28.                                                                                                                                                                                                                                                                             |
| nonce         | uint64 (Go)                               | Giá trị dùng để định danh duy nhất cho một giao dịch của người gửi. Nếu hai giao dịch có cùng một giá trị số dùng một lần do người gửi tạo ra, chỉ có một giao dịch sẽ được thực thi.                                                                                                                                                    |
| giá gas       | \*big.Int (Go)                            | Đơn giá của gas tính bằng `peb` mà người gửi sẽ dùng để thanh toán phí giao dịch. Số tiền phí giao dịch được tính theo công thức `gas` \* `gasPrice`. Ví dụ: nếu giao dịch tốn 10 đơn vị gas và gasPrice là 10^18, phí giao dịch sẽ là 10 KLAY. Hãy xem [Đơn vị của KLAY](/content/klaytn/design/klaytn-native-coin-klay#units-of-klay). |
| gas           | uint64 (Go)                               | Lượng gas tối đa mà giao dịch được phép sử dụng.                                                                                                                                                                                                                                                                                         |
| đến           | \*common.Address (Go)                     | Địa chỉ tài khoản sẽ nhận giá trị được chuyển. Hiện tại giá trị này phải bằng 0. Tính năng xác định địa chỉ sẽ được hỗ trợ trong tương lai.                                                                                                                                                                                              |
| giá trị       | \*big.Int (Go)                            | Số lượng KLAY tính bằng `peb` sẽ được chuyển.                                                                                                                                                                                                                                                                                            |
| từ            | common.Address (Go)                       | Địa chỉ của người gửi. Để biết thêm chi tiết, hãy xem [Xác thực chữ ký của giao dịch](/content/klaytn/design/transactions#signature-validation-of-transactions).                                                                                                                                                                         |
| nhập          | \[]byte (Go)                              | Dữ liệu được gắn kèm giao dịch, dùng để thực thi giao dịch.                                                                                                                                                                                                                                                                              |
| humanReadable | bool (Go)                                 | Đây phải là giá trị false vì địa chỉ có thể đọc chưa được hỗ trợ. Nếu giá trị là true, giao dịch sẽ bị từ chối.                                                                                                                                                                                                                          |
| codeFormat    | uint8 (Go)                                | Định dạng mã của mã hợp đồng thông minh. Hiện tại, giá trị được hỗ trợ chỉ có EVM(0x00).                                                                                                                                                                                                                                                 |
| txSignatures  | \[]{\*big.Int, \*big.Int, \*big.Int} (Go) | Chữ ký của người gửi. Để biết thêm chi tiết, hãy xem [Xác thực chữ ký của giao dịch](/content/klaytn/design/transactions#signature-validation-of-transactions).                                                                                                                                                                          |

### Mã hóa RLP cho chữ ký <a href="#rlp-encoding-for-signature" id="rlp-encoding-for-signature"></a>

Để tạo chữ ký của loại giao dịch này, quá trình tuần tự hóa RLP phải diễn ra như sau:

```javascript
SigRLP = encode([encode([type, nonce, gasPrice, gas, to, value, from, input, humanReadable, codeFormat]), chainid, 0, 0])
SigHash = keccak256(SigRLP)
Signature = sign(SigHash, <private key>)
```

### Mã hóa RLP cho SenderTxHash <a href="#rlp-encoding-for-sendertxhash" id="rlp-encoding-for-sendertxhash"></a>

Để tạo một SenderTxHash, quá trình tuần tự hóa RLP phải diễn ra như sau:

```javascript
txSignatures (a single signature) = [[v, r, s]]
txSignatures (two signatures) = [[v1, r1, s1], [v2, r2, s2]]
SenderTxHashRLP = type + encode([nonce, gasPrice, gas, to, value, from, input, humanReadable, codeFormat, txSignatures])
SenderTxHash = keccak256(SenderTxHashRLP)
```

### Mã hóa RLP cho hàm băm giao dịch <a href="#rlp-encoding-for-transaction-hash" id="rlp-encoding-for-transaction-hash"></a>

Để tạo một chữ ký giao dịch của người trả phí, quá trình tuần tự hóa RLP phải diễn ra như sau:

```javascript
txSignatures (a single signature) = [[v, r, s]]
txSignatures (two signatures) = [[v1, r1, s1], [v2, r2, s2]]
TxHashRLP = type + encode([nonce, gasPrice, gas, to, value, from, input, humanReadable, codeFormat, txSignatures])
TxHash = keccak256(TxHashRLP)
```

### Mã hóa RLP (Ví dụ) <a href="#rlp-encoding-example" id="rlp-encoding-example"></a>

Phần dưới đây cho thấy kết quả của quá trình tuần tự hóa RLP và đối tượng giao dịch:

```javascript
ChainID 0x1
PrivateKey 0x45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8
PublicKey.X 0x3a514176466fa815ed481ffad09110a2d344f6c9b78c1d14afc351c3a51be33d
PublicKey.Y 0x8072e77939dc03ba44790779b7a1025baf3003f6732430e20cd9b76d953391b3
SigRLP 0xf90240b9023af90237288204d219830f4240947b65b75d204abed71587c9e519a89277766ee1d00a94a94f5374fce5edbc8e2a8697c15331677e6ebf0bb901fe608060405234801561001057600080fd5b506101de806100206000396000f3006080604052600436106100615763ffffffff7c01000000000000000000000000000000000000000000000000000000006000350416631a39d8ef81146100805780636353586b146100a757806370a08231146100ca578063fd6b7ef8146100f8575b3360009081526001602052604081208054349081019091558154019055005b34801561008c57600080fd5b5061009561010d565b60408051918252519081900360200190f35b6100c873ffffffffffffffffffffffffffffffffffffffff60043516610113565b005b3480156100d657600080fd5b5061009573ffffffffffffffffffffffffffffffffffffffff60043516610147565b34801561010457600080fd5b506100c8610159565b60005481565b73ffffffffffffffffffffffffffffffffffffffff1660009081526001602052604081208054349081019091558154019055565b60016020526000908152604090205481565b336000908152600160205260408120805490829055908111156101af57604051339082156108fc029083906000818181858888f193505050501561019c576101af565b3360009081526001602052604090208190555b505600a165627a7a72305820627ca46bb09478a015762806cc00c431230501118c7c26c30ac58c4e09e51c4f00290180018080
SigHash 0xa921fa892d5dec0837bd32c1fb77fc3b2df57ec0b0c4eea79192c79883ed543c
Signature f845f84325a0fcd107738fb47750ba727610aefd6d5f51ac8163d62ce500e7ab7e15defe7088a0383d68220d0266490ea4173c1d7847f22fcbe22f8c8125e1c0589189845c902a
TxHashRLP 0x28f9027d8204d219830f4240947b65b75d204abed71587c9e519a89277766ee1d00a94a94f5374fce5edbc8e2a8697c15331677e6ebf0bb901fe608060405234801561001057600080fd5b506101de806100206000396000f3006080604052600436106100615763ffffffff7c01000000000000000000000000000000000000000000000000000000006000350416631a39d8ef81146100805780636353586b146100a757806370a08231146100ca578063fd6b7ef8146100f8575b3360009081526001602052604081208054349081019091558154019055005b34801561008c57600080fd5b5061009561010d565b60408051918252519081900360200190f35b6100c873ffffffffffffffffffffffffffffffffffffffff60043516610113565b005b3480156100d657600080fd5b5061009573ffffffffffffffffffffffffffffffffffffffff60043516610147565b34801561010457600080fd5b506100c8610159565b60005481565b73ffffffffffffffffffffffffffffffffffffffff1660009081526001602052604081208054349081019091558154019055565b60016020526000908152604090205481565b336000908152600160205260408120805490829055908111156101af57604051339082156108fc029083906000818181858888f193505050501561019c576101af565b3360009081526001602052604090208190555b505600a165627a7a72305820627ca46bb09478a015762806cc00c431230501118c7c26c30ac58c4e09e51c4f00290180f845f84325a0fcd107738fb47750ba727610aefd6d5f51ac8163d62ce500e7ab7e15defe7088a0383d68220d0266490ea4173c1d7847f22fcbe22f8c8125e1c0589189845c902a
TxHash e983f38b814891990f3ca57028c2230dc7e907eb313c827e7c99fadcc9b4c58b
SenderTxHashRLP 0x28f9027d8204d219830f4240947b65b75d204abed71587c9e519a89277766ee1d00a94a94f5374fce5edbc8e2a8697c15331677e6ebf0bb901fe608060405234801561001057600080fd5b506101de806100206000396000f3006080604052600436106100615763ffffffff7c01000000000000000000000000000000000000000000000000000000006000350416631a39d8ef81146100805780636353586b146100a757806370a08231146100ca578063fd6b7ef8146100f8575b3360009081526001602052604081208054349081019091558154019055005b34801561008c57600080fd5b5061009561010d565b60408051918252519081900360200190f35b6100c873ffffffffffffffffffffffffffffffffffffffff60043516610113565b005b3480156100d657600080fd5b5061009573ffffffffffffffffffffffffffffffffffffffff60043516610147565b34801561010457600080fd5b506100c8610159565b60005481565b73ffffffffffffffffffffffffffffffffffffffff1660009081526001602052604081208054349081019091558154019055565b60016020526000908152604090205481565b336000908152600160205260408120805490829055908111156101af57604051339082156108fc029083906000818181858888f193505050501561019c576101af565b3360009081526001602052604090208190555b505600a165627a7a72305820627ca46bb09478a015762806cc00c431230501118c7c26c30ac58c4e09e51c4f00290180f845f84325a0fcd107738fb47750ba727610aefd6d5f51ac8163d62ce500e7ab7e15defe7088a0383d68220d0266490ea4173c1d7847f22fcbe22f8c8125e1c0589189845c902a
SenderTxHash e983f38b814891990f3ca57028c2230dc7e907eb313c827e7c99fadcc9b4c58b

    TX(e983f38b814891990f3ca57028c2230dc7e907eb313c827e7c99fadcc9b4c58b)
    Type:          TxTypeSmartContractDeploy
    From:          0xa94f5374Fce5edBC8E2a8697C15331677e6EbF0B
    To:            0x7b65B75d204aBed71587c9E519a89277766EE1d0
    Nonce:         1234
    GasPrice:      0x19
    GasLimit:      0xf4240
    Value:         0xa
    Signature:     [{"V":"0x25","R":"0xfcd107738fb47750ba727610aefd6d5f51ac8163d62ce500e7ab7e15defe7088","S":"0x383d68220d0266490ea4173c1d7847f22fcbe22f8c8125e1c0589189845c902a"}]
    Data:          363038303630343035323334383031353631303031303537363030303830666435623530363130316465383036313030323036303030333936303030663330303630383036303430353236303034333631303631303036313537363366666666666666663763303130303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303630303033353034313636333161333964386566383131343631303038303537383036333633353335383662313436313030613735373830363337306130383233313134363130306361353738303633666436623765663831343631303066383537356233333630303039303831353236303031363032303532363034303831323038303534333439303831303139303931353538313534303139303535303035623334383031353631303038633537363030303830666435623530363130303935363130313064353635623630343038303531393138323532353139303831393030333630323030313930663335623631303063383733666666666666666666666666666666666666666666666666666666666666666666666666666666663630303433353136363130313133353635623030356233343830313536313030643635373630303038306664356235303631303039353733666666666666666666666666666666666666666666666666666666666666666666666666666666663630303433353136363130313437353635623334383031353631303130343537363030303830666435623530363130306338363130313539353635623630303035343831353635623733666666666666666666666666666666666666666666666666666666666666666666666666666666663136363030303930383135323630303136303230353236303430383132303830353433343930383130313930393135353831353430313930353535363562363030313630323035323630303039303831353236303430393032303534383135363562333336303030393038313532363030313630323035323630343038313230383035343930383239303535393038313131313536313031616635373630343035313333393038323135363130386663303239303833393036303030383138313831383538383838663139333530353035303530313536313031396335373631303161663536356233333630303039303831353236303031363032303532363034303930323038313930353535623530353630306131363536323761376137323330353832303632376361343662623039343738613031353736323830366363303063343331323330353031313138633763323663333061633538633465303965353163346630303239
    HumanReadable: true
    CodeFormat:    CodeFormatEVM
    Hex:           28f9027d8204d219830f4240947b65b75d204abed71587c9e519a89277766ee1d00a94a94f5374fce5edbc8e2a8697c15331677e6ebf0bb901fe608060405234801561001057600080fd5b506101de806100206000396000f3006080604052600436106100615763ffffffff7c01000000000000000000000000000000000000000000000000000000006000350416631a39d8ef81146100805780636353586b146100a757806370a08231146100ca578063fd6b7ef8146100f8575b3360009081526001602052604081208054349081019091558154019055005b34801561008c57600080fd5b5061009561010d565b60408051918252519081900360200190f35b6100c873ffffffffffffffffffffffffffffffffffffffff60043516610113565b005b3480156100d657600080fd5b5061009573ffffffffffffffffffffffffffffffffffffffff60043516610147565b34801561010457600080fd5b506100c8610159565b60005481565b73ffffffffffffffffffffffffffffffffffffffff1660009081526001602052604081208054349081019091558154019055565b60016020526000908152604090205481565b336000908152600160205260408120805490829055908111156101af57604051339082156108fc029083906000818181858888f193505050501561019c576101af565b3360009081526001602052604090208190555b505600a165627a7a72305820627ca46bb09478a015762806cc00c431230501118c7c26c30ac58c4e09e51c4f00290180f845f84325a0fcd107738fb47750ba727610aefd6d5f51ac8163d62ce500e7ab7e15defe7088a0383d68220d0266490ea4173c1d7847f22fcbe22f8c8125e1c0589189845c902a
```

### Kết quả đầu ra RPC (Example) <a href="#rpc-output-example" id="rpc-output-example"></a>

Phần dưới đây cho thấy một đối tượng giao dịch được trả về qua JSON RPC.

```javascript
{
  "blockHash": "0x82983fe294d286e76486760e6904369285554e1744af16786c2393a956fb4ec4",
  "blockNumber": "0x2",
  "codeFormat": "0x0",
  "contractAddress": "0x636f6e74726163742e6b6c6179746e0000000000",
  "from": "0x0fcda0f2efbe1b4e61b487701ce4f2f8abc3723d",
  "gas": "0x174876e800",
  "gasPrice": "0x0",
  "gasUsed": "0xee6e343d",
  "humanReadable": true,
  "input": "0x608060405234801561001057600080fd5b506101de806100206000396000f3006080604052600436106100615763ffffffff7c01000000000000000000000000000000000000000000000000000000006000350416631a39d8ef81146100805780636353586b146100a757806370a08231146100ca578063fd6b7ef8146100f8575b3360009081526001602052604081208054349081019091558154019055005b34801561008c57600080fd5b5061009561010d565b60408051918252519081900360200190f35b6100c873ffffffffffffffffffffffffffffffffffffffff60043516610113565b005b3480156100d657600080fd5b5061009573ffffffffffffffffffffffffffffffffffffffff60043516610147565b34801561010457600080fd5b506100c8610159565b60005481565b73ffffffffffffffffffffffffffffffffffffffff1660009081526001602052604081208054349081019091558154019055565b60016020526000908152604090205481565b336000908152600160205260408120805490829055908111156101af57604051339082156108fc029083906000818181858888f193505050501561019c576101af565b3360009081526001602052604090208190555b505600a165627a7a72305820627ca46bb09478a015762806cc00c431230501118c7c26c30ac58c4e09e51c4f0029",
  "nhật ký": [],
  "nhật kýBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
  "nonce": "0xa",
  "senderTxHash": "0x78a5633ee5b453ed2f00937e65945a3b76e96623634e1555e2f15d44930168af",
  "signatures": [
    {
      "V": "0x25",
      "R": "0x369d892dc24786111fd8f0308e8a6518708727257e95b3281865508faa0a768b",
      "S": "0x12fc22c390a89484d1cb70e1f19c4fa8a203b1406044ee9c263264876f0dd724"
    }
  ],
  "trạng thái": "0x1",
  "to": "0x636f6e74726163742e6b6c6179746e0000000000",
  "transactionHash": "0x78a5633ee5b453ed2f00937e65945a3b76e96623634e1555e2f15d44930168af",
  "transactionIndex": "0x3",
  "type": "TxTypeSmartContractDeploy",
  "typeInt": 40,
  "value": "0x0"
}
```

## TxTypeSmartContractExecution <a href="#txtypesmartcontractexecution" id="txtypesmartcontractexecution"></a>

TxTypeSmartContractExecution thực thi hợp đồng thông minh với dữ liệu đã cho trong `input`. TxTypeSmartContractExecution chỉ được chấp nhận nếu `to` là một tài khoản hợp đồng thông minh. Để chuyển KLAY đến một tài khoản sở hữu bên ngoài, hãy dùng [TxTypeValueTransfer](#txtypevaluetransfer). Các thay đổi sau sẽ được tạo ra nhờ loại giao dịch này.

1. Nếu `to` là một tài khoản hợp đồng thông minh, mã sẽ được thực thi dựa trên `input`. Nếu không, giao dịch sẽ bị từ chối.
2. Số dư của người gửi giảm đi một lượng bằng khoản phí giao dịch.
3. Số dùng một lần của người gửi tăng thêm một đơn vị.
4. Nếu `value` được cung cấp, `value` KLAY được chuyển từ người gửi đến `to` của hợp đồng thông minh. Hợp đồng phải có hàm dự phòng khoản phải trả để nhận KLAY.

### Thuộc tính <a href="#attributes" id="attributes"></a>

| Thuộc tính   | Loại                                     | Mô tả                                                                                                                                                                                                                                                                                                                                    |
| ------------ | ----------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| type         | uint8 (Go)                                | Loại TxTypeSmartContractExecution. Thuộc tính này phải là 0x30.                                                                                                                                                                                                                                                                          |
| nonce        | uint64 (Go)                               | Giá trị dùng để định danh duy nhất cho một giao dịch của người gửi. Nếu hai giao dịch có cùng một giá trị số dùng một lần do người gửi tạo ra, chỉ có một giao dịch sẽ được thực thi.                                                                                                                                                    |
| giá gas      | \*big.Int (Go)                            | Đơn giá của gas tính bằng `peb` mà người gửi sẽ dùng để thanh toán phí giao dịch. Số tiền phí giao dịch được tính theo công thức `gas` \* `gasPrice`. Ví dụ: nếu giao dịch tốn 10 đơn vị gas và gasPrice là 10^18, phí giao dịch sẽ là 10 KLAY. Hãy xem [Đơn vị của KLAY](/content/klaytn/design/klaytn-native-coin-klay#units-of-klay). |
| gas          | uint64 (Go)                               | Lượng gas tối đa mà giao dịch được phép sử dụng.                                                                                                                                                                                                                                                                                         |
| đến          | common.Address (Go)                       | Địa chỉ thực thi tài khoản hợp đồng thông minh.                                                                                                                                                                                                                                                                                          |
| giá trị      | \*big.Int (Go)                            | Số lượng KLAY tính bằng `peb` sẽ được chuyển.                                                                                                                                                                                                                                                                                            |
| từ           | common.Address (Go)                       | Địa chỉ của người gửi. Để biết thêm chi tiết, hãy xem [Xác thực chữ ký của giao dịch](/content/klaytn/design/transactions#signature-validation-of-transactions).                                                                                                                                                                         |
| nhập         | \[]byte (Go)                              | Dữ liệu được gắn kèm giao dịch, dùng để thực thi giao dịch.                                                                                                                                                                                                                                                                              |
| txSignatures | \[]{\*big.Int, \*big.Int, \*big.Int} (Go) | Chữ ký của người gửi. Để biết thêm chi tiết, hãy xem [Xác thực chữ ký của giao dịch](/content/klaytn/design/transactions#signature-validation-of-transactions).                                                                                                                                                                          |

### Mã hóa RLP cho chữ ký <a href="#rlp-encoding-for-signature" id="rlp-encoding-for-signature"></a>

Để tạo chữ ký của loại giao dịch này, quá trình tuần tự hóa RLP phải diễn ra như sau:

```javascript
SigRLP = encode([encode([type, nonce, gasPrice, gas, to, value, from, input]), chainid, 0, 0])
SigHash = keccak256(SigRLP)
Signature = sign(SigHash, <private key>)
```

### Mã hóa RLP cho SenderTxHash <a href="#rlp-encoding-for-sendertxhash" id="rlp-encoding-for-sendertxhash"></a>

Để tạo một SenderTxHash, quá trình tuần tự hóa RLP phải diễn ra như sau:

```javascript
txSignatures (a single signature) = [[v, r, s]]
txSignatures (two signatures) = [[v1, r1, s1], [v2, r2, s2]]
SenderTxHashRLP = type + encode([nonce, gasPrice, gas, to, value, from, input, txSignatures])
SenderTxHash = keccak256(SenderTxHashRLP)
```

### Mã hóa RLP cho hàm băm giao dịch <a href="#rlp-encoding-for-transaction-hash" id="rlp-encoding-for-transaction-hash"></a>

Để tạo một hàm băm giao dịch, quá trình tuần tự hóa RLP phải diễn ra như sau:

```javascript
txSignatures (a single signature) = [[v, r, s]]
txSignatures (two signatures) = [[v1, r1, s1], [v2, r2, s2]]
TxHashRLP = type + encode([nonce, gasPrice, gas, to, value, from, input, txSignatures])
TxHash = keccak256(TxHashRLP)
```

### Mã hóa RLP (Ví dụ) <a href="#rlp-encoding-example" id="rlp-encoding-example"></a>

Phần dưới đây cho thấy kết quả của quá trình tuần tự hóa RLP và đối tượng giao dịch:

```javascript
ChainID 0x1
PrivateKey 0x45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8
PublicKey.X 0x3a514176466fa815ed481ffad09110a2d344f6c9b78c1d14afc351c3a51be33d
PublicKey.Y 0x8072e77939dc03ba44790779b7a1025baf3003f6732430e20cd9b76d953391b3
SigRLP 0xf860b85bf859308204d219830f4240947b65b75d204abed71587c9e519a89277766ee1d00a94a94f5374fce5edbc8e2a8697c15331677e6ebf0ba46353586b000000000000000000000000bc5951f055a85f41a3b62fd6f68ab7de76d299b2018080
SigHash 0x197ea7d262f74489934d6cbcf8baa3bec169c16ad672fef4a9f8148864c9cdce
Signature f845f84326a0e4276df1a779274fbb04bc18a0184809eec1ce9770527cebb3d64f926dc1810ba04103b828a0671a48d64fe1a3879eae229699f05a684d9c5fd939015dcdd9709b
TxHashRLP 0x30f89f8204d219830f4240947b65b75d204abed71587c9e519a89277766ee1d00a94a94f5374fce5edbc8e2a8697c15331677e6ebf0ba46353586b000000000000000000000000bc5951f055a85f41a3b62fd6f68ab7de76d299b2f845f84326a0e4276df1a779274fbb04bc18a0184809eec1ce9770527cebb3d64f926dc1810ba04103b828a0671a48d64fe1a3879eae229699f05a684d9c5fd939015dcdd9709b
TxHash 23bb192bd58d56527843eb63225c5213f3aded95e4c9776f1ff0bdd8ee0b6826
SenderTxHashRLP 0x30f89f8204d219830f4240947b65b75d204abed71587c9e519a89277766ee1d00a94a94f5374fce5edbc8e2a8697c15331677e6ebf0ba46353586b000000000000000000000000bc5951f055a85f41a3b62fd6f68ab7de76d299b2f845f84326a0e4276df1a779274fbb04bc18a0184809eec1ce9770527cebb3d64f926dc1810ba04103b828a0671a48d64fe1a3879eae229699f05a684d9c5fd939015dcdd9709b
SenderTxHash 23bb192bd58d56527843eb63225c5213f3aded95e4c9776f1ff0bdd8ee0b6826

    TX(23bb192bd58d56527843eb63225c5213f3aded95e4c9776f1ff0bdd8ee0b6826)
    Type:          TxTypeSmartContractExecution
    From:          0xa94f5374Fce5edBC8E2a8697C15331677e6EbF0B
    To:            0x7b65B75d204aBed71587c9E519a89277766EE1d0
    Nonce:         1234
    GasPrice:      0x19
    GasLimit:      0xf4240
    Value:         0xa
    Signature:     [{"V":"0x26","R":"0xe4276df1a779274fbb04bc18a0184809eec1ce9770527cebb3d64f926dc1810b","S":"0x4103b828a0671a48d64fe1a3879eae229699f05a684d9c5fd939015dcdd9709b"}]
    Data:          363335333538366230303030303030303030303030303030303030303030303062633539353166303535613835663431613362363266643666363861623764653736643239396232
    Hex:           30f89f8204d219830f4240947b65b75d204abed71587c9e519a89277766ee1d00a94a94f5374fce5edbc8e2a8697c15331677e6ebf0ba46353586b000000000000000000000000bc5951f055a85f41a3b62fd6f68ab7de76d299b2f845f84326a0e4276df1a779274fbb04bc18a0184809eec1ce9770527cebb3d64f926dc1810ba04103b828a0671a48d64fe1a3879eae229699f05a684d9c5fd939015dcdd9709b
```

### Kết quả đầu ra RPC (Example) <a href="#rpc-output-example" id="rpc-output-example"></a>

Phần dưới đây cho thấy một đối tượng giao dịch được trả về qua JSON RPC.

```javascript
{
  "blockHash": "0x82983fe294d286e76486760e6904369285554e1744af16786c2393a956fb4ec4",
  "blockNumber": "0x2",
  "contractAddress": null,
  "from": "0x0fcda0f2efbe1b4e61b487701ce4f2f8abc3723d",
  "gas": "0x174876e800",
  "gasPrice": "0x5d21dba00",
  "gasUsed": "0xfedc",
  "input": "0x6353586b0000000000000000000000000fcda0f2efbe1b4e61b487701ce4f2f8abc3723d",
  "nhật ký": [],
  "nhật kýBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
  "nonce": "0xd",
  "senderTxHash": "0xe216873dedd72d8d67a9f5e51eb5a7ed2b5f34bca334adff7a3601d6d3e2e132",
  "signatures": [
    {
      "V": "0x26",
      "R": "0x68fe3dfd1ff3ea14427f157b5837cb6eb0b00fd0497e1c80897de1935200f0",
      "S": "0x6b84fbedcb4ff785120890596fad3f797c178cda8908f3b02ee0a4442fbf4189"
    }
  ],
  "trạng thái": "0x1",
  "to": "0x636f6e74726163742e6b6c6179746e0000000000",
  "transactionHash": "0xe216873dedd72d8d67a9f5e51eb5a7ed2b5f34bca334adff7a3601d6d3e2e132",
  "transactionIndex": "0x6",
  "type": "TxTypeSmartContractExecution",
  "typeInt": 48,
  "value": "0xa"
}
```

## TxTypeAccountUpdate <a href="#txtypeaccountupdate" id="txtypeaccountupdate"></a>

TxTypeAccountUpdate cập nhật khóa của tài khoản đã cho. Các thay đổi sau sẽ được áp dụng nhờ loại giao dịch này.

1. Số dư của người gửi giảm đi một lượng bằng khoản phí giao dịch.
2. Số dùng một lần của người gửi tăng thêm một đơn vị.
3. Khóa tài khoản được cập nhật bằng `key`.
4. Khi loại giao dịch này đã được triển khai, các giao dịch gửi từ tài khoản này từ đó sẽ được xác thực bằng `key` mới.

### Thuộc tính <a href="#attributes" id="attributes"></a>

| Thuộc tính   | type                                      | Mô tả                                                                                                                                                                                                                                                                                                                                                |
| ------------ | ----------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| type         | uint8 (Go)                                | Loại TxTypeAccountUpdate. Thuộc tính này phải là 0x20.                                                                                                                                                                                                                                                                                               |
| nonce        | uint64 (Go)                               | Giá trị dùng để định danh duy nhất cho một giao dịch của người gửi. Nếu hai giao dịch có cùng một giá trị số dùng một lần do người gửi tạo ra, chỉ có một giao dịch sẽ được thực thi.                                                                                                                                                                |
| giá gas      | \*big.Int (Go)                            | Hệ số nhân để tính toán số lượng token mà người gửi sẽ thanh toán. Lượng token mà người gửi sẽ thanh toán được tính theo công thức `gas` \* `gasPrice`. Ví dụ: Người gửi sẽ thanh toán khoản phí giao dịch là 10 KLAY nếu gas bằng 10 và gasPrice là 10^18. Hãy xem [Đơn vị của KLAY](/content/klaytn/design/klaytn-native-coin-klay#units-of-klay). |
| gas          | uint64 (Go)                               | Giá trị phí giao dịch tối đa mà giao dịch được phép sử dụng.                                                                                                                                                                                                                                                                                         |
| từ           | common.Address (Go)                       | Địa chỉ của người gửi. Để biết thêm chi tiết, hãy xem [Xác thực chữ ký của giao dịch](/content/klaytn/design/transactions#signature-validation-of-transactions).                                                                                                                                                                                     |
| khóa         | AccountKey (Go)                           | \[AccountKey]\[] cần cập nhật cho tài khoản.                                                                                                                                                                                                                                                                                                         |
| txSignatures | \[]{\*big.Int, \*big.Int, \*big.Int} (Go) | Chữ ký của người gửi. Để biết thêm chi tiết, hãy xem [Xác thực chữ ký của giao dịch](/content/klaytn/design/transactions#signature-validation-of-transactions).                                                                                                                                                                                      |

### Mã hóa RLP cho chữ ký <a href="#rlp-encoding-for-signature" id="rlp-encoding-for-signature"></a>

Để tạo chữ ký của loại giao dịch này, quá trình tuần tự hóa RLP phải diễn ra như sau:

```javascript
SigRLP = encode([encode([type, nonce, gasPrice, gas, from, rlpEncodedKey]), chainid, 0, 0])
SigHash = keccak256(SigRLP)
Signature = sign(SigHash, <private key>)
```

### Mã hóa RLP cho SenderTxHash <a href="#rlp-encoding-for-sendertxhash" id="rlp-encoding-for-sendertxhash"></a>

Để tạo một SenderTxHash, quá trình tuần tự hóa RLP phải diễn ra như sau:

```javascript
txSignatures (a single signature) = [[v, r, s]]
txSignatures (two signatures) = [[v1, r1, s1], [v2, r2, s2]]
SenderTxHashRLP = type + encode([nonce, gasPrice, gas, from, rlpEncodedKey, txSignatures])
SenderTxHash = keccak256(SenderTxHashRLP)
```

### Mã hóa RLP cho hàm băm giao dịch <a href="#rlp-encoding-for-transaction-hash" id="rlp-encoding-for-transaction-hash"></a>

Để tạo một hàm băm giao dịch, quá trình tuần tự hóa RLP phải diễn ra như sau:

```javascript
txSignatures (a single signature) = [[v, r, s]]
txSignatures (two signatures) = [[v1, r1, s1], [v2, r2, s2]]
TxHashRLP = type + encode([nonce, gasPrice, gas, from, rlpEncodedKey, txSignatures])
TxHash = keccak256(TxHashRLP)
```

### Mã hóa RLP (Ví dụ) <a href="#rlp-encoding-example" id="rlp-encoding-example"></a>

Phần dưới đây cho thấy kết quả của quá trình tuần tự hóa RLP và đối tượng giao dịch:

```javascript
ChainID 0x1
PrivateKey 0x45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8
PublicKey.X 0x3a514176466fa815ed481ffad09110a2d344f6c9b78c1d14afc351c3a51be33d
PublicKey.Y 0x8072e77939dc03ba44790779b7a1025baf3003f6732430e20cd9b76d953391b3
SigRLP 0xf849b844f842208204d219830f424094a94f5374fce5edbc8e2a8697c15331677e6ebf0ba302a1033a514176466fa815ed481ffad09110a2d344f6c9b78c1d14afc351c3a51be33d018080
SigHash 0xa0d3f1d2b4f061c3a5d9c22c7bb621aa821162b42b4db6cf1888defc2473e0ab
Signature f845f84325a0f7d479628f05f51320f0842193e3f7ae55a5b49d3645bf55c35bee1e8fd2593aa04de8eab5338fdc86e96f8c49ed516550f793fc2c4007614ce3d2a6b33cf9e451
TxHashRLP 0x20f8888204d219830f424094a94f5374fce5edbc8e2a8697c15331677e6ebf0ba302a1033a514176466fa815ed481ffad09110a2d344f6c9b78c1d14afc351c3a51be33df845f84325a0f7d479628f05f51320f0842193e3f7ae55a5b49d3645bf55c35bee1e8fd2593aa04de8eab5338fdc86e96f8c49ed516550f793fc2c4007614ce3d2a6b33cf9e451
TxHash 8c70627d6b637c7d033ead083fc5e43e5cad10c704a86dd9bda7ac104a0e5ad0
SenderTxHashRLP 0x20f8888204d219830f424094a94f5374fce5edbc8e2a8697c15331677e6ebf0ba302a1033a514176466fa815ed481ffad09110a2d344f6c9b78c1d14afc351c3a51be33df845f84325a0f7d479628f05f51320f0842193e3f7ae55a5b49d3645bf55c35bee1e8fd2593aa04de8eab5338fdc86e96f8c49ed516550f793fc2c4007614ce3d2a6b33cf9e451
SenderTxHash 8c70627d6b637c7d033ead083fc5e43e5cad10c704a86dd9bda7ac104a0e5ad0

    TX(8c70627d6b637c7d033ead083fc5e43e5cad10c704a86dd9bda7ac104a0e5ad0)
    Type:          TxTypeAccountUpdate
    From:          0xa94f5374Fce5edBC8E2a8697C15331677e6EbF0B
    Nonce:         1234
    GasPrice:      0x19
    GasLimit:      0xf4240
    Key:           AccountKeyPublic: S256Pubkey:{"x":"0x3a514176466fa815ed481ffad09110a2d344f6c9b78c1d14afc351c3a51be33d","y":"0x8072e77939dc03ba44790779b7a1025baf3003f6732430e20cd9b76d953391b3"}
    Signature:     [{"V":"0x25","R":"0xf7d479628f05f51320f0842193e3f7ae55a5b49d3645bf55c35bee1e8fd2593a","S":"0x4de8eab5338fdc86e96f8c49ed516550f793fc2c4007614ce3d2a6b33cf9e451"}]
    Hex:           20f8888204d219830f424094a94f5374fce5edbc8e2a8697c15331677e6ebf0ba302a1033a514176466fa815ed481ffad09110a2d344f6c9b78c1d14afc351c3a51be33df845f84325a0f7d479628f05f51320f0842193e3f7ae55a5b49d3645bf55c35bee1e8fd2593aa04de8eab5338fdc86e96f8c49ed516550f793fc2c4007614ce3d2a6b33cf9e451
```

### Kết quả đầu ra RPC (Example) <a href="#rpc-output-example" id="rpc-output-example"></a>

Phần dưới đây cho thấy một đối tượng giao dịch được trả về qua JSON RPC.

```javascript
{
  "blockHash": "0x82983fe294d286e76486760e6904369285554e1744af16786c2393a956fb4ec4",
  "blockNumber": "0x2",
  "contractAddress": null,
  "from": "0x636f6c696e2e6b6c6179746e0000000000000000",
  "gas": "0x174876e800",
  "gasPrice": "0x5d21dba00",
  "gasUsed": "0xa028",
  "key": "0x02a1034ef27ba4b7d1ae09b166744c5b7ee4a7a0cc5c76b2e5d74523a0a4fb56db3191",
  "nhật ký": [],
  "nhật kýBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
  "nonce": "0x0",
  "senderTxHash": "0x3f154903f92a179007b45b807af2d971ada9a23657e80bf5c18a75ac6516fd0b",
  "signatures": [
    {
      "V": "0x25",
      "R": "0x757827ec43eafdc150ecb35423699ceaea41b13dd07f8620e2231a7b0e278149",
      "S": "0x59d43ed3e0ed0f9d69d0c08ccca29913a8b138c000029f878f61337220a1ca1b"
    }
  ],
  "trạng thái": "0x1",
  "transactionHash": "0x3f154903f92a179007b45b807af2d971ada9a23657e80bf5c18a75ac6516fd0b",
  "transactionIndex": "0x0",
  "type": "TxTypeAccountUpdate",
  "typeInt": 32
}
```

## TxTypeCancel <a href="#txtypecancel" id="txtypecancel"></a>

TxTypeCancel hủy bỏ việc thực thi giao dịch có cùng số dùng một lần trong bể giao dịch. Loại giao dịch này có ích khi một giao dịch đã gửi có vẻ như không được xử lý trong một khoảng thời gian nhất định. Có một số trường hợp mà một giao dịch có vẻ như không được xử lý: 1. Giao dịch bị thất lạc ở đâu đó và không đi đến bất kỳ một nút đồng thuận nào. 2. Giao dịch chưa được xử lý tại bất kỳ một nút đồng thuận nào. 3. Giao dịch đã được xử lý nhưng khối chứa giao dịch này đã không được nhận.

Từ phía máy khách, rất khó để biết được lí do chính xác là gì, bởi vì để tìm ra lý do đó, ta cần phải xem nội dung bên trong của tất cả các nút đồng thuận. Tuy nhiên, việc kết nối với bất kỳ nút đồng thuận nào từ phía công chúng đều bị cấm. Trong trường hợp này, trong các nền tảng chuỗi khối thông thường, người dùng thường gửi một giao dịch khác với một giá gas cao hơn để thay thế giao dịch cũ. Tuy nhiên, bởi vì trong Klaytn, giá gas là cố định, việc thay thế giao dịch vũ bằng giá gas cao hơn là không khả thi.

Nếu giao dịch vẫn không được xử lý, các giao dịch khác với số dùng một lần cao hơn cũng sẽ không thể được xử lý, vì số dùng một lần xác định thứ tự thực thi của các giao dịch.

Để giải quyết vấn đề này, Klaytn cung cấp một loại giao dịch TxTypeCancel. Nếu người dùng gặp phải trường hợp như vậy, họ có thể gửi giao dịch TxTypeCancel.

Từng trường hợp nêu trên có thể được xử lý như sau: 1. Nếu giao dịch cũ bị thất lạc, giao dịch TxTypeCancel này sẽ được thực thi và đưa vào một khối. 2. Nếu giao dịch cũ vẫn chưa được xử lý, giao dịch TxType Cancel này sẽ thay thế giao dịch cũ. Sau đó, nó được thực thi và đưa vào một khối. 3. nếu giao dịch cũ đã được triển khai, số dùng một lần đã tăng lên, giao dịch TxTypeCancel này sẽ bị loại bỏ vì có số dùng một lần thấp hơn.

Lưu ý rằng giao dịch TxTypeCancel là giao dịch duy nhất có khả năng thay thế một giao dịch với cùng một số dùng một lần. Các loại giao dịch khác không thể thay thế các giao dịch với cùng một số dùng một lần.

Các thay đổi sau có thể xuất hiện do loại giao dịch này. 1. Số dư của người gửi giảm đi một lượng bằng khoản phí giao dịch. 2. Số dùng một lần của người gửi tăng thêm một đơn vị.

### Thuộc tính <a href="#attributes" id="attributes"></a>

| Thuộc tính   | Loại                                     | Mô tả                                                                                                                                                                                                                                                                                                                                    |
| ------------ | ----------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| type         | uint8 (Go)                                | Loại TxTypeCancel. Thuộc tính này phải là 0x38.                                                                                                                                                                                                                                                                                          |
| nonce        | uint64 (Go)                               | Giá trị dùng để định danh duy nhất cho một giao dịch của người gửi. Nếu hai giao dịch có cùng một giá trị số dùng một lần do người gửi tạo ra, chỉ có một giao dịch sẽ được thực thi. Đối với giao dịch `TxTypeCancel`, giá trị này phải khớp với số dùng một lần mà giao dịch đích cần hủy đang sử dụng.                                |
| giá gas      | \*big.Int (Go)                            | Đơn giá của gas tính bằng `peb` mà người gửi sẽ dùng để thanh toán phí giao dịch. Số tiền phí giao dịch được tính theo công thức `gas` \* `gasPrice`. Ví dụ: nếu giao dịch tốn 10 đơn vị gas và gasPrice là 10^18, phí giao dịch sẽ là 10 KLAY. Hãy xem [Đơn vị của KLAY](/content/klaytn/design/klaytn-native-coin-klay#units-of-klay). |
| gas          | uint64 (Go)                               | Giá trị phí giao dịch tối đa mà giao dịch được phép sử dụng.                                                                                                                                                                                                                                                                             |
| từ           | common.Address (Go)                       | Địa chỉ của người gửi. Để biết thêm chi tiết, hãy xem [Xác thực chữ ký của giao dịch](/content/klaytn/design/transactions#signature-validation-of-transactions).                                                                                                                                                                         |
| txSignatures | \[]{\*big.Int, \*big.Int, \*big.Int} (Go) | Chữ ký của người gửi. Để biết thêm chi tiết, hãy xem [Xác thực chữ ký của giao dịch](/content/klaytn/design/transactions#signature-validation-of-transactions).                                                                                                                                                                          |

Kết quả:

1. Nếu một giao dịch có cùng số dùng một lần, nó sẽ được thay thế bởi giao dịch hủy này.
2. Nếu số dùng một lần không giống nhau, giao dịch này sẽ chỉ được đưa vào như một giao dịch bình thường.
3. Giao dịch hủy không được thay thế bằng những loại giao dịch khác.

### Mã hóa RLP cho chữ ký <a href="#rlp-encoding-for-signature" id="rlp-encoding-for-signature"></a>

Để tạo một chữ ký giao dịch, quá trình tuần tự hóa RLP phải diễn ra như sau:

```javascript
SigRLP = encode([encode([type, nonce, gasPrice, gas, from]), chainid, 0, 0])
SigHash = keccak256(SigRLP)
Signature = sign(SigHash, <private key>)
```

### Mã hóa RLP cho SenderTxHash <a href="#rlp-encoding-for-sendertxhash" id="rlp-encoding-for-sendertxhash"></a>

Để tạo một SenderTxHash, quá trình tuần tự hóa RLP phải diễn ra như sau:

```javascript
txSignatures (a single signature) = [[v, r, s]]
txSignatures (two signatures) = [[v1, r1, s1], [v2, r2, s2]]
SenderTxHashRLP = type + encode([nonce, gasPrice, gas, from, txSignatures])
SenderTxHash = keccak256(SenderTxHashRLP)
```

### Mã hóa RLP cho hàm băm giao dịch <a href="#rlp-encoding-for-transaction-hash" id="rlp-encoding-for-transaction-hash"></a>

Để tạo một hàm băm giao dịch, quá trình tuần tự hóa RLP phải diễn ra như sau:

```javascript
txSignatures (a single signature) = [[v, r, s]]
txSignatures (two signatures) = [[v1, r1, s1], [v2, r2, s2]]
TxHashRLP = type + encode([nonce, gasPrice, gas, from, txSignatures])
TxHash = keccak256(TxHashRLP)
```

### Mã hóa RLP (Ví dụ) <a href="#rlp-encoding-example" id="rlp-encoding-example"></a>

Phần dưới đây cho thấy kết quả của quá trình tuần tự hóa RLP và đối tượng giao dịch:

```javascript
ChainID 0x1
PrivateKey 0x45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8
PublicKey.X 0x3a514176466fa815ed481ffad09110a2d344f6c9b78c1d14afc351c3a51be33d
PublicKey.Y 0x8072e77939dc03ba44790779b7a1025baf3003f6732430e20cd9b76d953391b3
SigRLP 0xe39fde388204d219830f424094a94f5374fce5edbc8e2a8697c15331677e6ebf0b018080
SigHash 0xaaac6d71ad921e8a12e92c47d0b0654a20d8d9a4ff70d83f78661ccdf062ce9a
Signature f845f84325a0fb2c3d53d2f6b7bb1deb5a09f80366a5a45429cc1e3956687b075a9dcad20434a05c6187822ee23b1001e9613d29a5d6002f990498d2902904f7f259ab3358216e
TxHashRLP 0x38f8648204d219830f424094a94f5374fce5edbc8e2a8697c15331677e6ebf0bf845f84325a0fb2c3d53d2f6b7bb1deb5a09f80366a5a45429cc1e3956687b075a9dcad20434a05c6187822ee23b1001e9613d29a5d6002f990498d2902904f7f259ab3358216e
TxHash 10d135d590cb587cc45c1f94f4a0e3b8c24d24a6e4243f09ca395fb4e2450413
SenderTxHashRLP 0x38f8648204d219830f424094a94f5374fce5edbc8e2a8697c15331677e6ebf0bf845f84325a0fb2c3d53d2f6b7bb1deb5a09f80366a5a45429cc1e3956687b075a9dcad20434a05c6187822ee23b1001e9613d29a5d6002f990498d2902904f7f259ab3358216e
SenderTxHash 10d135d590cb587cc45c1f94f4a0e3b8c24d24a6e4243f09ca395fb4e2450413

    TX(10d135d590cb587cc45c1f94f4a0e3b8c24d24a6e4243f09ca395fb4e2450413)
    Type:          TxTypeCancel
    From:          0xa94f5374Fce5edBC8E2a8697C15331677e6EbF0B
    Nonce:         1234
    GasPrice:      0x19
    GasLimit:      0xf4240
    Signature:     [{"V":"0x25","R":"0xfb2c3d53d2f6b7bb1deb5a09f80366a5a45429cc1e3956687b075a9dcad20434","S":"0x5c6187822ee23b1001e9613d29a5d6002f990498d2902904f7f259ab3358216e"}]
    Hex:           38f8648204d219830f424094a94f5374fce5edbc8e2a8697c15331677e6ebf0bf845f84325a0fb2c3d53d2f6b7bb1deb5a09f80366a5a45429cc1e3956687b075a9dcad20434a05c6187822ee23b1001e9613d29a5d6002f990498d2902904f7f259ab3358216e
```

### Kết quả đầu ra RPC (Example) <a href="#rpc-output-example" id="rpc-output-example"></a>

Phần dưới đây cho thấy một đối tượng giao dịch được trả về qua JSON RPC.

```javascript
{
  "blockHash": "0x82983fe294d286e76486760e6904369285554e1744af16786c2393a956fb4ec4",
  "blockNumber": "0x2",
  "contractAddress": null,
  "from": "0x0fcda0f2efbe1b4e61b487701ce4f2f8abc3723d",
  "gas": "0x174876e800",
  "gasPrice": "0x5d21dba00",
  "gasUsed": "0x5208",
  "nhật ký": [],
  "nhật kýBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
  "nonce": "0x10",
  "senderTxHash": "0x0370adf89b2463d3d1fd894d6328929c931ef0cc3a8f1481affedd2e9c88d9d6",
  "signatures": [
    {
      "V": "0x26",
      "R": "0xad73f30acfb80090cba8d3f4be4696e65f8eb7c36b85aac06a9bea350d10578f",
      "S": "0x7ec2d6f052d8f916d12db2e0310381201888cb12d3a3696da80cab5195833706"
    }
  ],
  "trạng thái": "0x1",
  "transactionHash": "0x0370adf89b2463d3d1fd894d6328929c931ef0cc3a8f1481affedd2e9c88d9d6",
  "transactionIndex": "0x9",
  "type": "TxTypeCancel",
  "typeInt": 56
}
```

## TxTypeChainDataAnchoring <a href="#txtypechaindataanchoring" id="txtypechaindataanchoring"></a>

TxTypeChainDataAnchoringTransaction là một giao dịch neo dữ liệu chuỗi dịch vụ vào chuỗi chính của Klaytn. Các chuỗi dịch vụ gửi định kỳ loại giao dịch này đến chuỗi chính Klaytn để đảm bảo tính bảo mật và độ tin cậy của dữ liệu. Để biết thêm chi tiết về việc neo dữ liệu, hãy xem [Neo](https://github.com/klaytn/klaytn-docs-vn/blob/main/docs/node/service-chain/references/anchoring.md). Lưu ý rằng giao dịch này không được phép gửi qua RPC. Hiện tại, giao dịch này được thực thi qua các kênh P2P riêng tư vì lý do bảo mật. Giao dịch này không làm thay đổi trạng thái của chuỗi khối Klaytn, ngoại trừ việc số dùng một lần của người gửi tăng lên một đơn vị.

### Thuộc tính <a href="#attributes" id="attributes"></a>

| Thuộc tính   | Loại                                     | Mô tả                                                                                                                                                                                                                                                                                                                                    |
| ------------ | ----------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| type         | uint8 (Go)                                | Loại TxTypeChainDataAnchoringTransaction. Thuộc tính này phải là 0x48.                                                                                                                                                                                                                                                                   |
| nonce        | uint64 (Go)                               | Giá trị dùng để định danh duy nhất cho một giao dịch của người gửi. Nếu hai giao dịch có cùng một giá trị số dùng một lần do người gửi tạo ra, chỉ có một giao dịch sẽ được thực thi.                                                                                                                                                    |
| giá gas      | \*big.Int (Go)                            | Đơn giá của gas tính bằng `peb` mà người gửi sẽ dùng để thanh toán phí giao dịch. Số tiền phí giao dịch được tính theo công thức `gas` \* `gasPrice`. Ví dụ: nếu giao dịch tốn 10 đơn vị gas và gasPrice là 10^18, phí giao dịch sẽ là 10 KLAY. Hãy xem [Đơn vị của KLAY](/content/klaytn/design/klaytn-native-coin-klay#units-of-klay). |
| gas          | uint64 (Go)                               | Giá trị phí giao dịch tối đa mà giao dịch được phép sử dụng.                                                                                                                                                                                                                                                                             |
| từ           | common.Address (Go)                       | Địa chỉ của người gửi. Để biết thêm chi tiết, hãy xem [Xác thực chữ ký của giao dịch](/content/klaytn/design/transactions#signature-validation-of-transactions).                                                                                                                                                                         |
| nhập         | \[]byte (Go)                              | Dữ liệu của chuỗi dịch vụ.                                                                                                                                                                                                                                                                                                               |
| txSignatures | \[]{\*big.Int, \*big.Int, \*big.Int} (Go) | Chữ ký của người gửi. Để biết thêm chi tiết, hãy xem [Xác thực chữ ký của giao dịch](/content/klaytn/design/transactions#signature-validation-of-transactions).                                                                                                                                                                          |

### Mã hóa RLP cho chữ ký <a href="#rlp-encoding-for-signature" id="rlp-encoding-for-signature"></a>

Để tạo chữ ký của loại giao dịch này, quá trình tuần tự hóa RLP phải diễn ra như sau:

```javascript
SigRLP = encode([encode([type, nonce, gasPrice, gas, from, anchoredData]), chainid, 0, 0])
SigHash = keccak256(SigRLP)
Signature = sign(SigHash, <private key>)
```

### Mã hóa RLP cho SenderTxHash <a href="#rlp-encoding-for-sendertxhash" id="rlp-encoding-for-sendertxhash"></a>

Để tạo một SenderTxHash, quá trình tuần tự hóa RLP phải diễn ra như sau:

```javascript
txSignatures (a single signature) = [[v, r, s]]
txSignatures (two signatures) = [[v1, r1, s1], [v2, r2, s2]]
SenderTxHashRLP = type + encode([nonce, gasPrice, gas, from, anchoredData, txSignatures])
SenderTxHash = keccak256(SenderTxHashRLP)
```

### Mã hóa RLP cho hàm băm giao dịch <a href="#rlp-encoding-for-transaction-hash" id="rlp-encoding-for-transaction-hash"></a>

Để tạo một hàm băm giao dịch, quá trình tuần tự hóa RLP phải diễn ra như sau:

```javascript
txSignatures (a single signature) = [[v, r, s]]
txSignatures (two signatures) = [[v1, r1, s1], [v2, r2, s2]]
TxHashRLP = type + encode([nonce, gasPrice, gas, from, anchoredData, txSignatures])
TxHash = keccak256(TxHashRLP)
```

### Mã hóa RLP (Ví dụ) <a href="#rlp-encoding-example" id="rlp-encoding-example"></a>

Phần dưới đây cho thấy kết quả của quá trình tuần tự hóa RLP và đối tượng giao dịch:

```javascript
ChainID 0x1
PrivateKey 0x45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8
PublicKey.X 0x3a514176466fa815ed481ffad09110a2d344f6c9b78c1d14afc351c3a51be33d
PublicKey.Y 0x8072e77939dc03ba44790779b7a1025baf3003f6732430e20cd9b76d953391b3
SigRLP 0xf8cfb8caf8c8488204d219830f424094a94f5374fce5edbc8e2a8697c15331677e6ebf0bb8a8f8a6a00000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000001a00000000000000000000000000000000000000000000000000000000000000002a00000000000000000000000000000000000000000000000000000000000000003a0000000000000000000000000000000000000000000000000000000000000000405018080
SigHash 0x07e07c69a12e384c16d94157c99d0a6fbae1d99f5d54501bfdc5937bbee7c792
Signature f845f84325a0e58b9abf9f33a066b998fccaca711553fb4df425c9234bbb3577f9d9775bb124a02c409a6c5d92277c0a812dd0cc553d7fe1d652a807274c3786df3292cd473e09
TxHashRLP 0x48f9010e8204d219830f424094a94f5374fce5edbc8e2a8697c15331677e6ebf0bb8a8f8a6a00000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000001a00000000000000000000000000000000000000000000000000000000000000002a00000000000000000000000000000000000000000000000000000000000000003a0000000000000000000000000000000000000000000000000000000000000000405f845f84325a0e58b9abf9f33a066b998fccaca711553fb4df425c9234bbb3577f9d9775bb124a02c409a6c5d92277c0a812dd0cc553d7fe1d652a807274c3786df3292cd473e09
TxHash 4aad85735e777795d24aa3eab51be959d8ebdf9683083d85b66f70b7170f2ea3
SenderTxHashRLP 0x48f9010e8204d219830f424094a94f5374fce5edbc8e2a8697c15331677e6ebf0bb8a8f8a6a00000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000001a00000000000000000000000000000000000000000000000000000000000000002a00000000000000000000000000000000000000000000000000000000000000003a0000000000000000000000000000000000000000000000000000000000000000405f845f84325a0e58b9abf9f33a066b998fccaca711553fb4df425c9234bbb3577f9d9775bb124a02c409a6c5d92277c0a812dd0cc553d7fe1d652a807274c3786df3292cd473e09
SenderTxHash 4aad85735e777795d24aa3eab51be959d8ebdf9683083d85b66f70b7170f2ea3

    TX(4aad85735e777795d24aa3eab51be959d8ebdf9683083d85b66f70b7170f2ea3)
    Type:          TxTypeChainDataAnchoring
    From:          0xa94f5374Fce5edBC8E2a8697C15331677e6EbF0B
    Nonce:         1234
    GasPrice:      0x19
    GasLimit:      0xf4240
    Signature:     [{"V":"0x25","R":"0xe58b9abf9f33a066b998fccaca711553fb4df425c9234bbb3577f9d9775bb124","S":"0x2c409a6c5d92277c0a812dd0cc553d7fe1d652a807274c3786df3292cd473e09"}]
    Hex:           48f9010e8204d219830f424094a94f5374fce5edbc8e2a8697c15331677e6ebf0bb8a8f8a6a00000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000001a00000000000000000000000000000000000000000000000000000000000000002a00000000000000000000000000000000000000000000000000000000000000003a0000000000000000000000000000000000000000000000000000000000000000405f845f84325a0e58b9abf9f33a066b998fccaca711553fb4df425c9234bbb3577f9d9775bb124a02c409a6c5d92277c0a812dd0cc553d7fe1d652a807274c3786df3292cd473e09
    AnchoredData:  f8a6a00000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000001a00000000000000000000000000000000000000000000000000000000000000002a00000000000000000000000000000000000000000000000000000000000000003a0000000000000000000000000000000000000000000000000000000000000000405
```

### Kết quả đầu ra RPC (Example) <a href="#rpc-output-example" id="rpc-output-example"></a>

Phần dưới đây cho thấy một đối tượng giao dịch được trả về qua JSON RPC.

```javascript
{
  "blockHash": "0x82983fe294d286e76486760e6904369285554e1744af16786c2393a956fb4ec4",
  "blockNumber": "0x2",
  "contractAddress": null,
  "from": "0x0fcda0f2efbe1b4e61b487701ce4f2f8abc3723d",
  "gas": "0x174876e800",
  "gasPrice": "0x5d21dba00",
  "gasUsed": "0x93a8",
  "input": "0xf8a6a00000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000001a00000000000000000000000000000000000000000000000000000000000000002a00000000000000000000000000000000000000000000000000000000000000003a0000000000000000000000000000000000000000000000000000000000000000405",
  "nhật ký": [],
  "nhật kýBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
  "nonce": "0x13",
  "senderTxHash": "0x28b56268d18b116b08b1673caad80212f271d6e36ceef225b44c6d2a1f0413db",
  "signatures": [
    {
      "V": "0x26",
      "R": "0x7049656869a9442d26ed0c2cbf15812dc486580d03f1cc6373104410225e1e7b",
      "S": "0x3c58fd9ae9390e6484e965572821846445983d9b5eb7866aa4113c56a5bf253e"
    }
  ],
  "trạng thái": "0x1",
  "transactionHash": "0x28b56268d18b116b08b1673caad80212f271d6e36ceef225b44c6d2a1f0413db",
  "transactionIndex": "0xc",
  "type": "TxTypeChainDataAnchoring",
  "typeInt": 72
}
```

\[AccountKeyLegacy]: ../tài khoảns.md#tài khoảnkeylegacy \[AccountKey]: ../tài khoảns.md#tài khoản-key


# Ủy thác phí

## TxTypeFeeDelegatedValueTransfer <a href="#txtypefeedelegatedvaluetransfer" id="txtypefeedelegatedvaluetransfer"></a>

TxTypeFeeDelegatedValueTransfer được sử dụng khi người dùng muốn gửi KLAY. Vì Klaytn cung cấp nhiều loại giao dịch sao cho mỗi loại giao dịch chỉ phục vụ một mục đích duy nhất, TxTypeFeeDelegatedValueTransfer bị giới hạn gửi KLAY đến một tài khoản thuộc sở hữu bên ngoài. Vì thế, TxTypeFeeDelegatedValueTransfer chỉ được chấp nhận nếu `to` là một tài khoản thuộc sở hữu bên ngoài. Để chuyển KLAY đến một tài khoản hợp đồng thông minh, hãy dùng [TxTypeFeeDelegatedSmartContractExecution](#txtypefeedelegatedsmartcontractexecution). Các thay đổi sau sẽ được tạo ra nhờ loại giao dịch này.

1. Số dư của người trả phí giảm đi một lượng bằng khoản phí giao dịch.
2. Số dùng một lần của người gửi tăng thêm một đơn vị.
3. `value` KLAY sẽ được chuyển từ người gửi đến người nhận.

### Thuộc tính <a href="#attributes" id="attributes"></a>

| Thuộc tính         | type                                      | Mô tả                                                                                                                                                                                                                                                                                                                                    |
| ------------------ | ----------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| type               | uint8 (Go)                                | Loại TxTypeFeeDelegatedValueTransfer. Thuộc tính này phải là 0x09.                                                                                                                                                                                                                                                                       |
| nonce              | uint64 (Go)                               | Giá trị dùng để định danh duy nhất cho một giao dịch của người gửi. Nếu hai giao dịch có cùng một giá trị số dùng một lần do người gửi tạo ra, chỉ có một giao dịch sẽ được thực thi.                                                                                                                                                    |
| giá gas            | \*big.Int (Go)                            | Đơn giá của gas tính bằng `peb` mà người gửi sẽ dùng để thanh toán phí giao dịch. Số tiền phí giao dịch được tính theo công thức `gas` \* `gasPrice`. Ví dụ: Nếu giao dịch tốn 10 đơn vị gas và gasPrice là 10^18, phí giao dịch sẽ là 10 KLAY. Hãy xem [Đơn vị của KLAY](/content/klaytn/design/klaytn-native-coin-klay#units-of-klay). |
| gas                | uint64 (Go)                               | Lượng gas tối đa mà giao dịch được phép sử dụng.                                                                                                                                                                                                                                                                                         |
| đến                | common.Address (Go)                       | Địa chỉ tài khoản sẽ nhận giá trị được chuyển.                                                                                                                                                                                                                                                                                           |
| giá trị            | \*big.Int (Go)                            | Số lượng KLAY tính bằng `peb` sẽ được chuyển.                                                                                                                                                                                                                                                                                            |
| từ                 | common.Address (Go)                       | Địa chỉ của người gửi. Để biết thêm chi tiết, hãy xem [Xác thực chữ ký của giao dịch](/content/klaytn/design/transactions#signature-validation-of-transactions).                                                                                                                                                                         |
| txSignatures       | \[]{\*big.Int, \*big.Int, \*big.Int} (Go) | Chữ ký của người gửi. Để biết thêm chi tiết, hãy xem [Xác thực chữ ký của giao dịch](/content/klaytn/design/transactions#signature-validation-of-transactions).                                                                                                                                                                          |
| feePayer           | common.Address (Go)                       | Địa chỉ của người trả phí.                                                                                                                                                                                                                                                                                                               |
| feePayerSignatures | \[]{\*big.Int, \*big.Int, \*big.Int} (Go) | Chữ ký của người trả phí.                                                                                                                                                                                                                                                                                                                |

### Mã hóa RLP cho chữ ký của người gửi <a href="#rlp-encoding-for-signature-of-the-sender" id="rlp-encoding-for-signature-of-the-sender"></a>

Để tạo chữ ký của người gửi, quá trình tuần tự hóa RLP phải diễn ra như sau:

```javascript
SigRLP = encode([encode([type, nonce, gasPrice, gas, to, value, from]), chainid, 0, 0])
SigHash = keccak256(SigRLP)
Signature = sign(SigHash, <the sender's private key>)
```

### Mã hóa RLP cho chữ ký của người trả phí <a href="#rlp-encoding-for-signature-of-the-fee-payer" id="rlp-encoding-for-signature-of-the-fee-payer"></a>

Để tạo chữ ký của người trả phí, quá trình tuần tự hóa RLP phải diễn ra như sau:

```javascript
SigFeePayerRLP = encode([ encode([type, nonce, gasPrice, gas, to, value, from]), feePayer, chainid, 0, 0 ])
SigFeePayerHash = keccak256(SigFeePayerRLP)
SignatureFeePayer = sign(SigFeePayerHash, <the fee payer's private key>)
```

### Mã hóa RLP cho SenderTxHash <a href="#rlp-encoding-for-sendertxhash" id="rlp-encoding-for-sendertxhash"></a>

Để tạo một SenderTxHash, quá trình tuần tự hóa RLP phải diễn ra như sau:

```javascript
txSignatures (a single signature) = [[v, r, s]]
txSignatures (two signatures) = [[v1, r1, s1], [v2, r2, s2]]
SenderTxHashRLP = type + encode([nonce, gasPrice, gas, to, value, from, txSignatures])
SenderTxHash = keccak256(SenderTxHashRLP)
```

### Mã hóa RLP cho hàm băm giao dịch <a href="#rlp-encoding-for-transaction-hash" id="rlp-encoding-for-transaction-hash"></a>

Để tạo một hàm băm giao dịch, quá trình tuần tự hóa RLP phải diễn ra như sau:

```javascript
txSignatures (a single signature) = [[v, r, s]]
txSignatures (two signatures) = [[v1, r1, s1], [v2, r2, s2]]
feePayerSignatures (a single signature) = [[v, r, s]]
feePayerSignatures (two signatures) = [[v1, r1, s1], [v2, r2, s2]]
TxHashRLP = type + encode([nonce, gasPrice, gas, to, value, from, txSignatures, feePayer, feePayerSignatures])`
TxHash = keccak256(TxHashRLP)
```

### Mã hóa RLP (Ví dụ) <a href="#rlp-encoding-example" id="rlp-encoding-example"></a>

Phần dưới đây cho thấy kết quả của quá trình tuần tự hóa RLP và đối tượng giao dịch:

```javascript
ChainID 0x1
PrivateKey 0x45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8
PublicKey.X 0x3a514176466fa815ed481ffad09110a2d344f6c9b78c1d14afc351c3a51be33d
PublicKey.Y 0x8072e77939dc03ba44790779b7a1025baf3003f6732430e20cd9b76d953391b3
SigRLP 0xf839b5f4098204d219830f4240947b65b75d204abed71587c9e519a89277766ee1d00a94a94f5374fce5edbc8e2a8697c15331677e6ebf0b018080
SigHash 0xb86e4cc0955f7c2cda1b36038c9d43a2724fc956c11e09c37625379b7eb2bd21
Signature f845f84325a09f8e49e2ad84b0732984398749956e807e4b526c786af3c5f7416b293e638956a06bf88342092f6ff9fabe31739b2ebfa1409707ce54a54693e91a6b9bb77df0e7
FeePayerPrivateKey 0xb9d5558443585bca6f225b935950e3f6e69f9da8a5809a83f51c3365dff53936
FeePayerPublicKey.X 0x327434d4cfc66ef8857d431419e9deebdc53a3e415edcc55382e2d417b8dd102
FeePayerPublicKey.Y 0x65fc97045707faf7b8f81ac65089d4cc71f69ad0bf1bc8559bc24f13fc284ced
SigRLPFeePayer 0xf84eb5f4098204d219830f4240947b65b75d204abed71587c9e519a89277766ee1d00a94a94f5374fce5edbc8e2a8697c15331677e6ebf0b945a0043070275d9f6054307ee7348bd660849d90f018080
SigHashFeePayer 0x3e7c5f40e826d1d22493be59bf62928dc397de5c972bd9bfa3fe5206c24a5f82
SignatureFeePayer f845f84326a0f45cf8d7f88c08e6b6ec0b3b562f34ca94283e4689021987abb6b0772ddfd80aa0298fe2c5aeabb6a518f4cbb5ff39631a5d88be505d3923374f65fdcf63c2955b
TxHashRLP 0x09f8d68204d219830f4240947b65b75d204abed71587c9e519a89277766ee1d00a94a94f5374fce5edbc8e2a8697c15331677e6ebf0bf845f84325a09f8e49e2ad84b0732984398749956e807e4b526c786af3c5f7416b293e638956a06bf88342092f6ff9fabe31739b2ebfa1409707ce54a54693e91a6b9bb77df0e7945a0043070275d9f6054307ee7348bd660849d90ff845f84326a0f45cf8d7f88c08e6b6ec0b3b562f34ca94283e4689021987abb6b0772ddfd80aa0298fe2c5aeabb6a518f4cbb5ff39631a5d88be505d3923374f65fdcf63c2955b
TxHash e1e07f9971153499fc8c7bafcdaf7abc20b37aa4c18fb1e53a9bfcc259e3644c
SenderTxHashRLP 0x09f87a8204d219830f4240947b65b75d204abed71587c9e519a89277766ee1d00a94a94f5374fce5edbc8e2a8697c15331677e6ebf0bf845f84325a09f8e49e2ad84b0732984398749956e807e4b526c786af3c5f7416b293e638956a06bf88342092f6ff9fabe31739b2ebfa1409707ce54a54693e91a6b9bb77df0e7
SenderTxHash 40f8c94e01e07eb5353f6cd4cd3eabd5893215dd53a50ba4b8ff9a447ac51731

    TX(e1e07f9971153499fc8c7bafcdaf7abc20b37aa4c18fb1e53a9bfcc259e3644c)
    Type:          TxTypeFeeDelegatedValueTransfer
    From:          0xa94f5374Fce5edBC8E2a8697C15331677e6EbF0B
    To:            0x7b65B75d204aBed71587c9E519a89277766EE1d0
    Nonce:         1234
    GasPrice:      0x19
    GasLimit:      0xf4240
    Value:         0xa
    Signature:     [{"V":"0x25","R":"0x9f8e49e2ad84b0732984398749956e807e4b526c786af3c5f7416b293e638956","S":"0x6bf88342092f6ff9fabe31739b2ebfa1409707ce54a54693e91a6b9bb77df0e7"}]
    FeePayer:      0x5A0043070275d9f6054307Ee7348bD660849D90f
    FeePayerSig:   [{"V":"0x26","R":"0xf45cf8d7f88c08e6b6ec0b3b562f34ca94283e4689021987abb6b0772ddfd80a","S":"0x298fe2c5aeabb6a518f4cbb5ff39631a5d88be505d3923374f65fdcf63c2955b"}]
    Hex:           09f8d68204d219830f4240947b65b75d204abed71587c9e519a89277766ee1d00a94a94f5374fce5edbc8e2a8697c15331677e6ebf0bf845f84325a09f8e49e2ad84b0732984398749956e807e4b526c786af3c5f7416b293e638956a06bf88342092f6ff9fabe31739b2ebfa1409707ce54a54693e91a6b9bb77df0e7945a0043070275d9f6054307ee7348bd660849d90ff845f84326a0f45cf8d7f88c08e6b6ec0b3b562f34ca94283e4689021987abb6b0772ddfd80aa0298fe2c5aeabb6a518f4cbb5ff39631a5d88be505d3923374f65fdcf63c2955b
```

### Kết quả đầu ra RPC (Example) <a href="#rpc-output-example" id="rpc-output-example"></a>

Phần dưới đây cho thấy một đối tượng giao dịch được trả về qua JSON RPC.

```javascript
{
  "blockHash": "0x7ad6ed1f9955be00db8fb5452125f0e9a3c0856abb5b4cc4aed91ffc134321da",
  "blockNumber": "0x1",
  "contractAddress": null,
  "feePayer": "0x029fdce0457db02f05c4be9f67b7115cb8ea15ca",
  "feePayerSignatures": [
    {
      "V": "0x26",
      "R": "0x984e9d43c496ef39ef2d496c8e1aee695f871e4f6cfae7f205ddda1589ca5c9e",
      "S": "0x46647d1ce8755cd664f5fb4eba3082dd1a13817488029f3869662986b7b1a5ae"
    }
  ],
  "from": "0x0fcda0f2efbe1b4e61b487701ce4f2f8abc3723d",
  "gas": "0x174876e800",
  "gasPrice": "0x5d21dba00",
  "gasUsed": "0x7918",
  "nhật ký": [],
  "nhật kýBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
  "nonce": "0x2",
  "senderTxHash": "0x6a8cf9a2f6d16561303445309d4f210c8be862f0d0c0e6f4998775fef9b4f957",
  "signatures": [
    {
      "V": "0x25",
      "R": "0x368b3324b37831b51711a2eba2a7608438a2bd5956ccecbcdb07d9163ff8bc87",
      "S": "0x7ee2e86ad6f01c867b2ced9d69e614ba22e539726451400fccdd56acbbc7a6f7"
    }
  ],
  "trạng thái": "0x1",
  "to": "0x75c3098be5e4b63fbac05838daaee378dd48098d",
  "transactionHash": "0xea4341b5c95fd5a0c3a8a15a4177ab6394725c24f722a9e31f53474a6dcf086a",
  "transactionIndex": "0x2",
  "type": "TxTypeFeeDelegatedValueTransfer",
  "typeInt": 9,
  "value": "0x21e19e0c9bab2400000"
}
```

## TxTypeFeeDelegatedValueTransferMemo <a href="#txtypefeedelegatedvaluetransfermemo" id="txtypefeedelegatedvaluetransfermemo"></a>

TxTypeFeeDelegatedValueTransferMemo được sử dụng khi người dùng muốn gửi KLAY với một tin nhắn cụ thể. TxTypeFeeDelegatedValueTransferMemo chỉ được chấp nhận nếu `to` là một tài khoản thuộc sở hữu bên ngoài. Để chuyển KLAY đến một tài khoản hợp đồng thông minh, hãy dùng [TxTypeFeeDelegatedSmartContractExecution](#txtypefeedelegatedsmartcontractexecution). Các thay đổi sau sẽ được tạo ra nhờ loại giao dịch này.

1. Số dư của người trả phí giảm đi một lượng bằng khoản phí giao dịch.
2. Số dùng một lần của người gửi tăng thêm một đơn vị.
3. `value` KLAY sẽ được chuyển từ người gửi đến người nhận.

### Thuộc tính <a href="#attributes" id="attributes"></a>

| Thuộc tính         | Mô tả                                     | Loại                                                                                                                                                                                                                                                                                                                                    | Một giá trị ví dụ |
| ------------------ | ----------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------- |
| type               | uint8 (Go)                                | Loại TxTypeFeeDelegatedValueTransferMemo. Thuộc tính này phải là 0x11.                                                                                                                                                                                                                                                                   |                   |
| nonce              | uint64 (Go)                               | Giá trị dùng để định danh duy nhất cho một giao dịch của người gửi. Nếu hai giao dịch có cùng một giá trị số dùng một lần do người gửi tạo ra, chỉ có một giao dịch sẽ được thực thi.                                                                                                                                                    |                   |
| giá gas            | \*big.Int (Go)                            | Đơn giá của gas tính bằng `peb` mà người gửi sẽ dùng để thanh toán phí giao dịch. Số tiền phí giao dịch được tính theo công thức `gas` \* `gasPrice`. Ví dụ: nếu giao dịch tốn 10 đơn vị gas và gasPrice là 10^18, phí giao dịch sẽ là 10 KLAY. Hãy xem [Đơn vị của KLAY](/content/klaytn/design/klaytn-native-coin-klay#units-of-klay). |                   |
| gas                | uint64 (Go)                               | Lượng gas tối đa mà giao dịch được phép sử dụng.                                                                                                                                                                                                                                                                                         |                   |
| đến                | common.Address (Go)                       | Địa chỉ tài khoản sẽ nhận giá trị được chuyển.                                                                                                                                                                                                                                                                                           |                   |
| giá trị            | \*big.Int (Go)                            | Số lượng KLAY tính bằng `peb` sẽ được chuyển.                                                                                                                                                                                                                                                                                            |                   |
| từ                 | common.Address (Go)                       | Địa chỉ của người gửi. Để biết thêm chi tiết, hãy xem [Xác thực chữ ký của giao dịch](/content/klaytn/design/transactions#signature-validation-of-transactions).                                                                                                                                                                         |                   |
| nhập               | \[]byte (Go)                              | Dữ liệu gắn kèm theo giao dịch. Thông điệp cần được truyền vào thuộc tính này.                                                                                                                                                                                                                                                           |                   |
| txSignatures       | \[]{\*big.Int, \*big.Int, \*big.Int} (Go) | Chữ ký của người gửi. Để biết thêm chi tiết, hãy xem [Xác thực chữ ký của giao dịch](/content/klaytn/design/transactions#signature-validation-of-transactions).                                                                                                                                                                          |                   |
| feePayer           | common.Address (Go)                       | Địa chỉ của người trả phí.                                                                                                                                                                                                                                                                                                               |                   |
| feePayerSignatures | \[]{\*big.Int, \*big.Int, \*big.Int} (Go) | Chữ ký của người trả phí.                                                                                                                                                                                                                                                                                                                |                   |

### Mã hóa RLP cho chữ ký của người gửi <a href="#rlp-encoding-for-signature-of-the-sender" id="rlp-encoding-for-signature-of-the-sender"></a>

Để tạo chữ ký của người gửi, quá trình tuần tự hóa RLP phải diễn ra như sau:

```javascript
SigRLP = encode([encode([type, nonce, gasPrice, gas, to, value, from, input]), chainid, 0, 0])
SigHash = keccak256(SigRLP)
Signature = sign(SigHash, <the sender's private key>)
```

### Mã hóa RLP cho chữ ký của người trả phí <a href="#rlp-encoding-for-signature-of-the-fee-payer" id="rlp-encoding-for-signature-of-the-fee-payer"></a>

Để tạo chữ ký của người trả phí, quá trình tuần tự hóa RLP phải diễn ra như sau:

```javascript
SigFeePayerRLP = encode([encode([type, nonce, gasPrice, gas, to, value, from, input]), feePayer, chainid, 0, 0])
SigFeePayerHash = keccak256(SigFeePayerRLP)
SignatureFeePayer = sign(SigFeePayerHash, <the fee payer's private key>)
```

### Mã hóa RLP cho SenderTxHash <a href="#rlp-encoding-for-sendertxhash" id="rlp-encoding-for-sendertxhash"></a>

Để tạo một SenderTxHash, quá trình tuần tự hóa RLP phải diễn ra như sau:

```javascript
txSignatures (a single signature) = [[v, r, s]]
txSignatures (two signatures) = [[v1, r1, s1], [v2, r2, s2]]
SenderTxHashRLP = type + encode([nonce, gasPrice, gas, to, value, from, input, txSignatures])
SenderTxHash = keccak256(SenderTxHashRLP)
```

### Mã hóa RLP cho hàm băm giao dịch <a href="#rlp-encoding-for-transaction-hash" id="rlp-encoding-for-transaction-hash"></a>

Để tạo một hàm băm giao dịch, quá trình tuần tự hóa RLP phải diễn ra như sau:

```javascript
txSignatures (a single signature) = [[v, r, s]]
txSignatures (two signatures) = [[v1, r1, s1], [v2, r2, s2]]
feePayerSignatures (a single signature) = [[v, r, s]]
feePayerSignatures (two signatures) = [[v1, r1, s1], [v2, r2, s2]]
TxHashRLP = type + encode([nonce, gasPrice, gas, to, value, from, input, txSignatures, feePayer, feePayerSignatures])
TxHash = keccak256(TxHashRLP)
```

### Mã hóa RLP (Ví dụ) <a href="#rlp-encoding-example" id="rlp-encoding-example"></a>

Phần dưới đây cho thấy kết quả của quá trình tuần tự hóa RLP và đối tượng giao dịch:

```javascript
ChainID 0x1
PrivateKey 0x45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8
PublicKey.X 0x3a514176466fa815ed481ffad09110a2d344f6c9b78c1d14afc351c3a51be33d
PublicKey.Y 0x8072e77939dc03ba44790779b7a1025baf3003f6732430e20cd9b76d953391b3
SigRLP 0xf841b83cf83a118204d219830f4240947b65b75d204abed71587c9e519a89277766ee1d00a94a94f5374fce5edbc8e2a8697c15331677e6ebf0b8568656c6c6f018080
SigHash 0x3333b9336d431ffa53b795fedcf03cc2217cea3f26825ea5cbf7d69f0b99fde9
Signature f845f84326a064e213aef0167fbd853f8f9989ef5d8b912a77457395ccf13d7f37009edd5c5ba05d0c2e55e4d8734fe2516ed56ac628b74c0eb02aa3b6eda51e1e25a1396093e1
FeePayerPrivateKey 0xb9d5558443585bca6f225b935950e3f6e69f9da8a5809a83f51c3365dff53936
FeePayerPublicKey.X 0x327434d4cfc66ef8857d431419e9deebdc53a3e415edcc55382e2d417b8dd102
FeePayerPublicKey.Y 0x65fc97045707faf7b8f81ac65089d4cc71f69ad0bf1bc8559bc24f13fc284ced
SigRLPFeePayer 0xf856b83cf83a118204d219830f4240947b65b75d204abed71587c9e519a89277766ee1d00a94a94f5374fce5edbc8e2a8697c15331677e6ebf0b8568656c6c6f945a0043070275d9f6054307ee7348bd660849d90f018080
SigHashFeePayer 0xed015096fb27764f576415e23576228cbf7c4fdad464ea7ffc3a1856dfe391c9
SignatureFeePayer f845f84326a087390ac14d3c34440b6ddb7b190d3ebde1a07d9a556e5a82ce7e501f24a060f9a037badbcb12cda1ed67b12b1831683a08a3adadee2ea760a07a46bdbb856fea44
TxHashRLP 0x11f8dc8204d219830f4240947b65b75d204abed71587c9e519a89277766ee1d00a94a94f5374fce5edbc8e2a8697c15331677e6ebf0b8568656c6c6ff845f84326a064e213aef0167fbd853f8f9989ef5d8b912a77457395ccf13d7f37009edd5c5ba05d0c2e55e4d8734fe2516ed56ac628b74c0eb02aa3b6eda51e1e25a1396093e1945a0043070275d9f6054307ee7348bd660849d90ff845f84326a087390ac14d3c34440b6ddb7b190d3ebde1a07d9a556e5a82ce7e501f24a060f9a037badbcb12cda1ed67b12b1831683a08a3adadee2ea760a07a46bdbb856fea44
TxHash 8f68882f6192a53ba470aeca1e83ed9b9e519906a91256724b284dee778b21c9
SenderTxHashRLP 0x11f8808204d219830f4240947b65b75d204abed71587c9e519a89277766ee1d00a94a94f5374fce5edbc8e2a8697c15331677e6ebf0b8568656c6c6ff845f84326a064e213aef0167fbd853f8f9989ef5d8b912a77457395ccf13d7f37009edd5c5ba05d0c2e55e4d8734fe2516ed56ac628b74c0eb02aa3b6eda51e1e25a1396093e1
SenderTxHash fffaa2b38d4e684ea70a89c78fc7b2659000d130c76ad721d68175cbfc77c550

    TX(8f68882f6192a53ba470aeca1e83ed9b9e519906a91256724b284dee778b21c9)
    Type:          TxTypeFeeDelegatedValueTransferMemo
    From:          0xa94f5374Fce5edBC8E2a8697C15331677e6EbF0B
    To:            0x7b65B75d204aBed71587c9E519a89277766EE1d0
    Nonce:         1234
    GasPrice:      0x19
    GasLimit:      0xf4240
    Value:         0xa
    Signature:     [{"V":"0x26","R":"0x64e213aef0167fbd853f8f9989ef5d8b912a77457395ccf13d7f37009edd5c5b","S":"0x5d0c2e55e4d8734fe2516ed56ac628b74c0eb02aa3b6eda51e1e25a1396093e1"}]
    FeePayer:      0x5A0043070275d9f6054307Ee7348bD660849D90f
    FeePayerSig:   [{"V":"0x26","R":"0x87390ac14d3c34440b6ddb7b190d3ebde1a07d9a556e5a82ce7e501f24a060f9","S":"0x37badbcb12cda1ed67b12b1831683a08a3adadee2ea760a07a46bdbb856fea44"}]
    Data:          36383635366336633666
    Hex:           11f8dc8204d219830f4240947b65b75d204abed71587c9e519a89277766ee1d00a94a94f5374fce5edbc8e2a8697c15331677e6ebf0b8568656c6c6ff845f84326a064e213aef0167fbd853f8f9989ef5d8b912a77457395ccf13d7f37009edd5c5ba05d0c2e55e4d8734fe2516ed56ac628b74c0eb02aa3b6eda51e1e25a1396093e1945a0043070275d9f6054307ee7348bd660849d90ff845f84326a087390ac14d3c34440b6ddb7b190d3ebde1a07d9a556e5a82ce7e501f24a060f9a037badbcb12cda1ed67b12b1831683a08a3adadee2ea760a07a46bdbb856fea44
```

### Kết quả đầu ra RPC (Example) <a href="#rpc-output-example" id="rpc-output-example"></a>

Phần dưới đây cho thấy một đối tượng giao dịch được trả về qua JSON RPC.

```javascript
{
  "blockHash": "0x7ad6ed1f9955be00db8fb5452125f0e9a3c0856abb5b4cc4aed91ffc134321da",
  "blockNumber": "0x1",
  "contractAddress": null,
  "feePayer": "0x029fdce0457db02f05c4be9f67b7115cb8ea15ca",
  "feePayerSignatures": [
    {
      "V": "0x25",
      "R": "0xb5d80dc924c51f58eb674a142ebfd8ca1c0bc722bc85b001a5a6905ba8226b1",
      "S": "0x79852418faacd4407aee4a461a08602fcf6a3a3cb63b9ba69d70ffe2f5fe3cd"
    }
  ],
  "from": "0x0fcda0f2efbe1b4e61b487701ce4f2f8abc3723d",
  "gas": "0x174876e800",
  "gasPrice": "0x5d21dba00",
  "gasUsed": "0x7b0c",
  "input": "0x68656c6c6f",
  "nhật ký": [],
  "nhật kýBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
  "nonce": "0x5",
  "senderTxHash": "0x5a4e42bac0b2bc8dda4ee82bfafc83e7f156f74d81d367a3db430abd40b2cd47",
  "signatures": [
    {
      "V": "0x26",
      "R": "0xe8f5484b057b542c80f16c5bb8707e040619c3dc9ac5628d2797aa3d8a2fc0d0",
      "S": "0x5d598f2f10283ded6f6e6a216f4278b27fdf4d431272fa090064ac0fd3fc8102"
    }
  ],
  "trạng thái": "0x1",
  "to": "0x75c3098be5e4b63fbac05838daaee378dd48098d",
  "transactionHash": "0x66fe4d1abdf15a250f9391646e0242c8e4c3310250ca316d8fd00856aac16172",
  "transactionIndex": "0x5",
  "type": "TxTypeFeeDelegatedValueTransferMemo",
  "typeInt": 17,
  "value": "0x989680"
}
```

## TxTypeFeeDelegatedSmartContractDeploy <a href="#txtypefeedelegatedsmartcontractdeploy" id="txtypefeedelegatedsmartcontractdeploy"></a>

TxTypeFeeDelegatedSmartContractDeploy triển khai một hợp đồng thông minh bằng giao dịch ủy thác phí. Các thay đổi sau sẽ được tạo ra nhờ loại giao dịch này.

1. Số dư của người trả phí giảm đi một lượng bằng khoản phí giao dịch.
2. Số dùng một lần của người gửi tăng thêm một đơn vị.
3. Một hợp đồng thông minh được triển khai bằng mã trong `input`. Địa chỉ đã triển khai sẽ được trả về qua `contractAddress` trong biên lai.
4. `value` KLAY sẽ được chuyển từ người gửi đến người nhận.

### Thuộc tính <a href="#attributes" id="attributes"></a>

| Thuộc tính         | type                                      | Mô tả                                                                                                                                                                                                                                                                                                                                    |
| ------------------ | ----------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| type               | uint8 (Go)                                | Loại TxTypeFeeDelegatedSmartContractDeploy. Thuộc tính này phải là 0x29.                                                                                                                                                                                                                                                                 |
| nonce              | uint64 (Go)                               | Giá trị dùng để định danh duy nhất cho một giao dịch của người gửi. Nếu hai giao dịch có cùng một giá trị số dùng một lần do người gửi tạo ra, chỉ có một giao dịch sẽ được thực thi.                                                                                                                                                    |
| giá gas            | \*big.Int (Go)                            | Đơn giá của gas tính bằng `peb` mà người gửi sẽ dùng để thanh toán phí giao dịch. Số tiền phí giao dịch được tính theo công thức `gas` \* `gasPrice`. Ví dụ: nếu giao dịch tốn 10 đơn vị gas và gasPrice là 10^18, phí giao dịch sẽ là 10 KLAY. Hãy xem [Đơn vị của KLAY](/content/klaytn/design/klaytn-native-coin-klay#units-of-klay). |
| gas                | uint64 (Go)                               | Lượng gas tối đa mà giao dịch được phép sử dụng.                                                                                                                                                                                                                                                                                         |
| đến                | \*common.Address (Go)                     | Địa chỉ tài khoản sẽ nhận giá trị được chuyển. Hiện tại giá trị này phải bằng 0. Tính năng xác định địa chỉ sẽ được hỗ trợ trong tương lai.                                                                                                                                                                                              |
| giá trị            | \*big.Int (Go)                            | Số lượng KLAY tính bằng `peb` sẽ được chuyển.                                                                                                                                                                                                                                                                                            |
| từ                 | common.Address (Go)                       | Địa chỉ của người gửi. Để biết thêm chi tiết, hãy xem [Xác thực chữ ký của giao dịch](/content/klaytn/design/transactions#signature-validation-of-transactions).                                                                                                                                                                         |
| nhập               | \[]byte (Go)                              | Dữ liệu được gắn kèm giao dịch, dùng để thực thi giao dịch.                                                                                                                                                                                                                                                                              |
| humanReadable      | bool (Go)                                 | Đây phải là giá trị false vì địa chỉ có thể đọc chưa được hỗ trợ. Nếu giá trị là true, giao dịch sẽ bị từ chối.                                                                                                                                                                                                                          |
| codeFormat         | uint8 (Go)                                | Định dạng mã của mã hợp đồng thông minh. Hiện tại, giá trị được hỗ trợ chỉ có EVM(0x00).                                                                                                                                                                                                                                                 |
| txSignatures       | \[]{\*big.Int, \*big.Int, \*big.Int} (Go) | Chữ ký của người gửi. Để biết thêm chi tiết, hãy xem [Xác thực chữ ký của giao dịch](/content/klaytn/design/transactions#signature-validation-of-transactions).                                                                                                                                                                          |
| feePayer           | common.Address (Go)                       | Địa chỉ của người trả phí.                                                                                                                                                                                                                                                                                                               |
| feePayerSignatures | \[]{\*big.Int, \*big.Int, \*big.Int} (Go) | Chữ ký của người trả phí.                                                                                                                                                                                                                                                                                                                |

### Mã hóa RLP cho chữ ký của người gửi <a href="#rlp-encoding-for-signature-of-the-sender" id="rlp-encoding-for-signature-of-the-sender"></a>

Để tạo chữ ký của người gửi, quá trình tuần tự hóa RLP phải diễn ra như sau:

```javascript
SigRLP = encode([encode([type, nonce, gasPrice, gas, to, value, from, input, humanReadable, codeFormat]), chainid, 0, 0])
SigHash = keccak256(SigRLP)
Signature = sign(SigHash, <the sender's private key>)
```

### Mã hóa RLP cho chữ ký của người trả phí <a href="#rlp-encoding-for-signature-of-the-fee-payer" id="rlp-encoding-for-signature-of-the-fee-payer"></a>

Để tạo chữ ký của người trả phí, quá trình tuần tự hóa RLP phải diễn ra như sau:

```javascript
SigFeePayerRLP = encode([encode([type, nonce, gasPrice, gas, to, value, from, input, humanReadable, codeFormat]), feePayer, chainid, 0, 0])
SigFeePayerHash = keccak256(SigFeePayerRLP)
SignatureFeePayer = sign(SigFeePayerHash, <the fee payer's private key>)
```

### Mã hóa RLP cho SenderTxHash <a href="#rlp-encoding-for-sendertxhash" id="rlp-encoding-for-sendertxhash"></a>

Để tạo một SenderTxHash, quá trình tuần tự hóa RLP phải diễn ra như sau:

```javascript
txSignatures (a single signature) = [[v, r, s]]
txSignatures (two signatures) = [[v1, r1, s1], [v2, r2, s2]]
SenderTxHashRLP = type + encode([nonce, gasPrice, gas, to, value, from, input,humanReadable, codeFormat, txSignatures])
SenderTxHash = keccak256(SenderTxHashRLP)
```

### Mã hóa RLP cho hàm băm giao dịch <a href="#rlp-encoding-for-transaction-hash" id="rlp-encoding-for-transaction-hash"></a>

Để tạo một hàm băm giao dịch, quá trình tuần tự hóa RLP phải diễn ra như sau:

```javascript
txSignatures (a single signature) = [[v, r, s]]
txSignatures (two signatures) = [[v1, r1, s1], [v2, r2, s2]]
feePayerSignatures (a single signature) = [[v, r, s]]
feePayerSignatures (two signatures) = [[v1, r1, s1], [v2, r2, s2]]
TxHashRLP = type + encode([nonce, gasPrice, gas, to, value, from, input, humanReadable, codeFormat, txSignatures, feePayer, feePayerSignatures])
TxHash = keccak256(TxHashRLP)
```

### Mã hóa RLP (Ví dụ) <a href="#rlp-encoding-example" id="rlp-encoding-example"></a>

Phần dưới đây cho thấy kết quả của quá trình tuần tự hóa RLP và đối tượng giao dịch:

```javascript
ChainID 0x1
PrivateKey 0x45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8
PublicKey.X 0x3a514176466fa815ed481ffad09110a2d344f6c9b78c1d14afc351c3a51be33d
PublicKey.Y 0x8072e77939dc03ba44790779b7a1025baf3003f6732430e20cd9b76d953391b3
SigRLP 0xf90240b9023af90237298204d219830f4240947b65b75d204abed71587c9e519a89277766ee1d00a94a94f5374fce5edbc8e2a8697c15331677e6ebf0bb901fe608060405234801561001057600080fd5b506101de806100206000396000f3006080604052600436106100615763ffffffff7c01000000000000000000000000000000000000000000000000000000006000350416631a39d8ef81146100805780636353586b146100a757806370a08231146100ca578063fd6b7ef8146100f8575b3360009081526001602052604081208054349081019091558154019055005b34801561008c57600080fd5b5061009561010d565b60408051918252519081900360200190f35b6100c873ffffffffffffffffffffffffffffffffffffffff60043516610113565b005b3480156100d657600080fd5b5061009573ffffffffffffffffffffffffffffffffffffffff60043516610147565b34801561010457600080fd5b506100c8610159565b60005481565b73ffffffffffffffffffffffffffffffffffffffff1660009081526001602052604081208054349081019091558154019055565b60016020526000908152604090205481565b336000908152600160205260408120805490829055908111156101af57604051339082156108fc029083906000818181858888f193505050501561019c576101af565b3360009081526001602052604090208190555b505600a165627a7a72305820627ca46bb09478a015762806cc00c431230501118c7c26c30ac58c4e09e51c4f00290180018080
SigHash 0xfd5e0726c763d117d07e5e688889ab7e4d0d1164d1bbca26a9d4ee629cbd875b
Signature f845f84325a04ea37b8ecfed93795a9f99b1e4d554df6fb05a361965a7655abd4e4c4422a9e5a00b05e3fffe5a3c0892eaff31466f6c47b7edad80703d395d65bbfc1a2c6a2570
FeePayerPrivateKey 0xb9d5558443585bca6f225b935950e3f6e69f9da8a5809a83f51c3365dff53936
FeePayerPublicKey.X 0x327434d4cfc66ef8857d431419e9deebdc53a3e415edcc55382e2d417b8dd102
FeePayerPublicKey.Y 0x65fc97045707faf7b8f81ac65089d4cc71f69ad0bf1bc8559bc24f13fc284ced
SigRLPFeePayer 0xf90255b9023af90237298204d219830f4240947b65b75d204abed71587c9e519a89277766ee1d00a94a94f5374fce5edbc8e2a8697c15331677e6ebf0bb901fe608060405234801561001057600080fd5b506101de806100206000396000f3006080604052600436106100615763ffffffff7c01000000000000000000000000000000000000000000000000000000006000350416631a39d8ef81146100805780636353586b146100a757806370a08231146100ca578063fd6b7ef8146100f8575b3360009081526001602052604081208054349081019091558154019055005b34801561008c57600080fd5b5061009561010d565b60408051918252519081900360200190f35b6100c873ffffffffffffffffffffffffffffffffffffffff60043516610113565b005b3480156100d657600080fd5b5061009573ffffffffffffffffffffffffffffffffffffffff60043516610147565b34801561010457600080fd5b506100c8610159565b60005481565b73ffffffffffffffffffffffffffffffffffffffff1660009081526001602052604081208054349081019091558154019055565b60016020526000908152604090205481565b336000908152600160205260408120805490829055908111156101af57604051339082156108fc029083906000818181858888f193505050501561019c576101af565b3360009081526001602052604090208190555b505600a165627a7a72305820627ca46bb09478a015762806cc00c431230501118c7c26c30ac58c4e09e51c4f00290180945a0043070275d9f6054307ee7348bd660849d90f018080
SigHashFeePayer 0xb7ea4d9d8c4d20ac6fd6cfffcaf89ae7d217d7450820b3b40d9ea29a0f01a1b2
SignatureFeePayer f845f84326a0c6738376304dfb32c77649bddd4ade925b947876cfe6b1fd2c06a2e4394504cca023817ba66a6b7c92fcf23f2d5506ea2a673aae5f1a1e4d742367971ae58a1576
TxHashRLP 0x29f902d98204d219830f4240947b65b75d204abed71587c9e519a89277766ee1d00a94a94f5374fce5edbc8e2a8697c15331677e6ebf0bb901fe608060405234801561001057600080fd5b506101de806100206000396000f3006080604052600436106100615763ffffffff7c01000000000000000000000000000000000000000000000000000000006000350416631a39d8ef81146100805780636353586b146100a757806370a08231146100ca578063fd6b7ef8146100f8575b3360009081526001602052604081208054349081019091558154019055005b34801561008c57600080fd5b5061009561010d565b60408051918252519081900360200190f35b6100c873ffffffffffffffffffffffffffffffffffffffff60043516610113565b005b3480156100d657600080fd5b5061009573ffffffffffffffffffffffffffffffffffffffff60043516610147565b34801561010457600080fd5b506100c8610159565b60005481565b73ffffffffffffffffffffffffffffffffffffffff1660009081526001602052604081208054349081019091558154019055565b60016020526000908152604090205481565b336000908152600160205260408120805490829055908111156101af57604051339082156108fc029083906000818181858888f193505050501561019c576101af565b3360009081526001602052604090208190555b505600a165627a7a72305820627ca46bb09478a015762806cc00c431230501118c7c26c30ac58c4e09e51c4f00290180f845f84325a04ea37b8ecfed93795a9f99b1e4d554df6fb05a361965a7655abd4e4c4422a9e5a00b05e3fffe5a3c0892eaff31466f6c47b7edad80703d395d65bbfc1a2c6a2570945a0043070275d9f6054307ee7348bd660849d90ff845f84326a0c6738376304dfb32c77649bddd4ade925b947876cfe6b1fd2c06a2e4394504cca023817ba66a6b7c92fcf23f2d5506ea2a673aae5f1a1e4d742367971ae58a1576
TxHash a457cc54b5cfd35eb61baa5ad61398fdcecab4c83693815addf00ca7166cb87e
SenderTxHashRLP 0x29f9027d8204d219830f4240947b65b75d204abed71587c9e519a89277766ee1d00a94a94f5374fce5edbc8e2a8697c15331677e6ebf0bb901fe608060405234801561001057600080fd5b506101de806100206000396000f3006080604052600436106100615763ffffffff7c01000000000000000000000000000000000000000000000000000000006000350416631a39d8ef81146100805780636353586b146100a757806370a08231146100ca578063fd6b7ef8146100f8575b3360009081526001602052604081208054349081019091558154019055005b34801561008c57600080fd5b5061009561010d565b60408051918252519081900360200190f35b6100c873ffffffffffffffffffffffffffffffffffffffff60043516610113565b005b3480156100d657600080fd5b5061009573ffffffffffffffffffffffffffffffffffffffff60043516610147565b34801561010457600080fd5b506100c8610159565b60005481565b73ffffffffffffffffffffffffffffffffffffffff1660009081526001602052604081208054349081019091558154019055565b60016020526000908152604090205481565b336000908152600160205260408120805490829055908111156101af57604051339082156108fc029083906000818181858888f193505050501561019c576101af565b3360009081526001602052604090208190555b505600a165627a7a72305820627ca46bb09478a015762806cc00c431230501118c7c26c30ac58c4e09e51c4f00290180f845f84325a04ea37b8ecfed93795a9f99b1e4d554df6fb05a361965a7655abd4e4c4422a9e5a00b05e3fffe5a3c0892eaff31466f6c47b7edad80703d395d65bbfc1a2c6a2570
SenderTxHash f3bca26fc8b50bfbcc1e94bc792ee6489cff14056e7e9aa2b074abb385f2139f

    TX(a457cc54b5cfd35eb61baa5ad61398fdcecab4c83693815addf00ca7166cb87e)
    Type:          TxTypeFeeDelegatedSmartContractDeploy
    From:          0xa94f5374Fce5edBC8E2a8697C15331677e6EbF0B
    To:            0x7b65B75d204aBed71587c9E519a89277766EE1d0
    Nonce:         1234
    GasPrice:      0x19
    GasLimit:      0xf4240
    Value:         0xa
    Data:          363038303630343035323334383031353631303031303537363030303830666435623530363130316465383036313030323036303030333936303030663330303630383036303430353236303034333631303631303036313537363366666666666666663763303130303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303630303033353034313636333161333964386566383131343631303038303537383036333633353335383662313436313030613735373830363337306130383233313134363130306361353738303633666436623765663831343631303066383537356233333630303039303831353236303031363032303532363034303831323038303534333439303831303139303931353538313534303139303535303035623334383031353631303038633537363030303830666435623530363130303935363130313064353635623630343038303531393138323532353139303831393030333630323030313930663335623631303063383733666666666666666666666666666666666666666666666666666666666666666666666666666666663630303433353136363130313133353635623030356233343830313536313030643635373630303038306664356235303631303039353733666666666666666666666666666666666666666666666666666666666666666666666666666666663630303433353136363130313437353635623334383031353631303130343537363030303830666435623530363130306338363130313539353635623630303035343831353635623733666666666666666666666666666666666666666666666666666666666666666666666666666666663136363030303930383135323630303136303230353236303430383132303830353433343930383130313930393135353831353430313930353535363562363030313630323035323630303039303831353236303430393032303534383135363562333336303030393038313532363030313630323035323630343038313230383035343930383239303535393038313131313536313031616635373630343035313333393038323135363130386663303239303833393036303030383138313831383538383838663139333530353035303530313536313031396335373631303161663536356233333630303039303831353236303031363032303532363034303930323038313930353535623530353630306131363536323761376137323330353832303632376361343662623039343738613031353736323830366363303063343331323330353031313138633763323663333061633538633465303965353163346630303239
    HumanReadable: true
    CodeFormat:    CodeFormatEVM
    Signature:     [{"V":"0x25","R":"0x4ea37b8ecfed93795a9f99b1e4d554df6fb05a361965a7655abd4e4c4422a9e5","S":"0xb05e3fffe5a3c0892eaff31466f6c47b7edad80703d395d65bbfc1a2c6a2570"}]
    FeePayer:      0x5A0043070275d9f6054307Ee7348bD660849D90f
    FeePayerSig:   [{"V":"0x26","R":"0xc6738376304dfb32c77649bddd4ade925b947876cfe6b1fd2c06a2e4394504cc","S":"0x23817ba66a6b7c92fcf23f2d5506ea2a673aae5f1a1e4d742367971ae58a1576"}]
    Hex:           29f902d98204d219830f4240947b65b75d204abed71587c9e519a89277766ee1d00a94a94f5374fce5edbc8e2a8697c15331677e6ebf0bb901fe608060405234801561001057600080fd5b506101de806100206000396000f3006080604052600436106100615763ffffffff7c01000000000000000000000000000000000000000000000000000000006000350416631a39d8ef81146100805780636353586b146100a757806370a08231146100ca578063fd6b7ef8146100f8575b3360009081526001602052604081208054349081019091558154019055005b34801561008c57600080fd5b5061009561010d565b60408051918252519081900360200190f35b6100c873ffffffffffffffffffffffffffffffffffffffff60043516610113565b005b3480156100d657600080fd5b5061009573ffffffffffffffffffffffffffffffffffffffff60043516610147565b34801561010457600080fd5b506100c8610159565b60005481565b73ffffffffffffffffffffffffffffffffffffffff1660009081526001602052604081208054349081019091558154019055565b60016020526000908152604090205481565b336000908152600160205260408120805490829055908111156101af57604051339082156108fc029083906000818181858888f193505050501561019c576101af565b3360009081526001602052604090208190555b505600a165627a7a72305820627ca46bb09478a015762806cc00c431230501118c7c26c30ac58c4e09e51c4f00290180f845f84325a04ea37b8ecfed93795a9f99b1e4d554df6fb05a361965a7655abd4e4c4422a9e5a00b05e3fffe5a3c0892eaff31466f6c47b7edad80703d395d65bbfc1a2c6a2570945a0043070275d9f6054307ee7348bd660849d90ff845f84326a0c6738376304dfb32c77649bddd4ade925b947876cfe6b1fd2c06a2e4394504cca023817ba66a6b7c92fcf23f2d5506ea2a673aae5f1a1e4d742367971ae58a1576
```

### Kết quả đầu ra RPC (Example) <a href="#rpc-output-example" id="rpc-output-example"></a>

Phần dưới đây cho thấy một đối tượng giao dịch được trả về qua JSON RPC.

```javascript
{
  "blockHash": "0x82983fe294d286e76486760e6904369285554e1744af16786c2393a956fb4ec4",
  "blockNumber": "0x2",
  "codeFormat": "0x0",
  "contractAddress": "0x636f6e7472616374322e6b6c6179746e00000000",
  "feePayer": "0x029fdce0457db02f05c4be9f67b7115cb8ea15ca",
  "feePayerSignatures": [
    {
      "V": "0x25",
      "R": "0x614fd887f4702627156132c9d56584207d1eaff529ee2967431eeaba924678f9",
      "S": "0x6b883a4467ca95a0ee75567062cb6d35629e9a22faeb8a711896488ce2cc4ed9"
    }
  ],
  "from": "0x0fcda0f2efbe1b4e61b487701ce4f2f8abc3723d",
  "gas": "0x174876e800",
  "gasPrice": "0x0",
  "gasUsed": "0xee6e5b4d",
  "humanReadable": true,
  "input": "0x608060405234801561001057600080fd5b506101de806100206000396000f3006080604052600436106100615763ffffffff7c01000000000000000000000000000000000000000000000000000000006000350416631a39d8ef81146100805780636353586b146100a757806370a08231146100ca578063fd6b7ef8146100f8575b3360009081526001602052604081208054349081019091558154019055005b34801561008c57600080fd5b5061009561010d565b60408051918252519081900360200190f35b6100c873ffffffffffffffffffffffffffffffffffffffff60043516610113565b005b3480156100d657600080fd5b5061009573ffffffffffffffffffffffffffffffffffffffff60043516610147565b34801561010457600080fd5b506100c8610159565b60005481565b73ffffffffffffffffffffffffffffffffffffffff1660009081526001602052604081208054349081019091558154019055565b60016020526000908152604090205481565b336000908152600160205260408120805490829055908111156101af57604051339082156108fc029083906000818181858888f193505050501561019c576101af565b3360009081526001602052604090208190555b505600a165627a7a72305820627ca46bb09478a015762806cc00c431230501118c7c26c30ac58c4e09e51c4f0029",
  "nhật ký": [],
  "nhật kýBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
  "nonce": "0xb",
  "senderTxHash": "0xf8f83c7a4a334430f403b20d84db492fac43ebabbd9676d731e11460d01a2160",
  "signatures": [
    {
      "V": "0x26",
      "R": "0xf3c521fea307b39bfa914b4835112bad18f89a627d639ddabe70c20af99d29a5",
      "S": "0x5179048cf993049b380f8cf7017c6e83b23da7883d2728208fe6161808594f44"
    }
  ],
  "trạng thái": "0x1",
  "to": "0x636f6e7472616374322e6b6c6179746e00000000",
  "transactionHash": "0x39b8a31f0c02a951615e3497d68a6534b8c8cc565e514ceafec53ee7ff50b8d9",
  "transactionIndex": "0x4",
  "type": "TxTypeFeeDelegatedSmartContractDeploy",
  "typeInt": 41,
  "value": "0x0"
}
```

## TxTypeFeeDelegatedSmartContractExecution <a href="#txtypefeedelegatedsmartcontractexecution" id="txtypefeedelegatedsmartcontractexecution"></a>

TxTypeFeeDelegatedSmartContractExecution thực thi hợp đồng thông minh với dữ liệu đã cho trong `input`. Người trả phí đã xác định sẽ thanh toán phí. TxTypeFeeDelegatedSmartContractExecution chỉ được chấp nhận nếu `to` là một tài khoản hợp đồng thông minh. Để chuyển KLAY đến một tài khoản sở hữu bên ngoài, hãy dùng [TxTypeFeeDelegatedValueTransfer](#txtypefeedelegatedvaluetransfer). Các thay đổi sau sẽ được tạo ra nhờ loại giao dịch này.

1. Nếu `to` là một tài khoản hợp đồng thông minh, mã sẽ được thực thi dựa trên `input`. Nếu không, giao dịch sẽ bị từ chối.
2. Số dư của người trả phí giảm đi một lượng bằng khoản phí giao dịch.
3. Số dùng một lần của người gửi tăng thêm một đơn vị.
4. Nếu `value` được cung cấp, `value` KLAY được chuyển từ người gửi đến `to` của hợp đồng thông minh. Hợp đồng phải có hàm dự phòng khoản phải trả để nhận KLAY.

### Thuộc tính <a href="#attributes" id="attributes"></a>

| Thuộc tính         | Loại                                     | Mô tả                                                                                                                                                                                                                                                                                                                                    |
| ------------------ | ----------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| type               | uint8 (Go)                                | Loại TxTypeFeeDelegatedSmartContractExecution. Thuộc tính này phải là 0x31.                                                                                                                                                                                                                                                              |
| nonce              | uint64 (Go)                               | Giá trị dùng để định danh duy nhất cho một giao dịch của người gửi. Nếu hai giao dịch có cùng một giá trị số dùng một lần do người gửi tạo ra, chỉ có một giao dịch sẽ được thực thi.                                                                                                                                                    |
| giá gas            | \*big.Int (Go)                            | Đơn giá của gas tính bằng `peb` mà người gửi sẽ dùng để thanh toán phí giao dịch. Số tiền phí giao dịch được tính theo công thức `gas` \* `gasPrice`. Ví dụ: Nếu giao dịch tốn 10 đơn vị gas và gasPrice là 10^18, phí giao dịch sẽ là 10 KLAY. Hãy xem [Đơn vị của KLAY](/content/klaytn/design/klaytn-native-coin-klay#units-of-klay). |
| gas                | uint64 (Go)                               | Lượng gas tối đa mà giao dịch được phép sử dụng.                                                                                                                                                                                                                                                                                         |
| đến                | common.Address (Go)                       | Địa chỉ thực thi tài khoản hợp đồng thông minh.                                                                                                                                                                                                                                                                                          |
| giá trị            | \*big.Int (Go)                            | Số lượng KLAY tính bằng `peb` sẽ được chuyển.                                                                                                                                                                                                                                                                                            |
| từ                 | common.Address (Go)                       | Địa chỉ của người gửi. Để biết thêm chi tiết, hãy xem [Xác thực chữ ký của giao dịch](/content/klaytn/design/transactions#signature-validation-of-transactions).                                                                                                                                                                         |
| nhập               | \[]byte (Go)                              | Dữ liệu được gắn kèm giao dịch, dùng để thực thi giao dịch.                                                                                                                                                                                                                                                                              |
| txSignatures       | \[]{\*big.Int, \*big.Int, \*big.Int} (Go) | Chữ ký của người gửi. Để biết thêm chi tiết, hãy xem [Xác thực chữ ký của giao dịch](/content/klaytn/design/transactions#signature-validation-of-transactions).                                                                                                                                                                          |
| feePayer           | common.Address (Go)                       | Địa chỉ của người trả phí.                                                                                                                                                                                                                                                                                                               |
| feePayerSignatures | \[]{\*big.Int, \*big.Int, \*big.Int} (Go) | Chữ ký của người trả phí.                                                                                                                                                                                                                                                                                                                |

### Mã hóa RLP cho chữ ký của người gửi <a href="#rlp-encoding-for-signature-of-the-sender" id="rlp-encoding-for-signature-of-the-sender"></a>

Để tạo chữ ký của người gửi, quá trình tuần tự hóa RLP phải diễn ra như sau:

```javascript
SigRLP = encode([encode([type, nonce, gasPrice, gas, to, value, from, input]), chainid, 0, 0])
SigHash = keccak256(SigRLP)
Signature = sign(SigHash, <the sender's private key>)
```

### Mã hóa RLP cho chữ ký của người trả phí <a href="#rlp-encoding-for-signature-of-the-fee-payer" id="rlp-encoding-for-signature-of-the-fee-payer"></a>

Để tạo chữ ký của người trả phí, quá trình tuần tự hóa RLP phải diễn ra như sau:

```javascript
SigFeePayerRLP = encode([encode([type, nonce, gasPrice, gas, to, value, from, input]), feePayer, chainid, 0, 0])
SigFeePayerHash = keccak256(SigFeePayerRLP)
SignatureFeePayer = sign(SigFeePayerHash, <the fee payer's private key>)
```

### Mã hóa RLP cho SenderTxHash <a href="#rlp-encoding-for-sendertxhash" id="rlp-encoding-for-sendertxhash"></a>

Để tạo một SenderTxHash, quá trình tuần tự hóa RLP phải diễn ra như sau:

```javascript
txSignatures (a single signature) = [[v, r, s]]
txSignatures (two signatures) = [[v1, r1, s1], [v2, r2, s2]]
SenderTxHashRLP = type + encode([nonce, gasPrice, gas, to, value, from, input, txSignatures])
SenderTxHash = keccak256(SenderTxHashRLP)
```

### Mã hóa RLP cho hàm băm giao dịch <a href="#rlp-encoding-for-transaction-hash" id="rlp-encoding-for-transaction-hash"></a>

Để tạo một hàm băm giao dịch, quá trình tuần tự hóa RLP phải diễn ra như sau:

```javascript
txSignatures (a single signature) = [[v, r, s]]
txSignatures (two signatures) = [[v1, r1, s1], [v2, r2, s2]]
feePayerSignatures (a single signature) = [[v, r, s]]
feePayerSignatures (two signatures) = [[v1, r1, s1], [v2, r2, s2]]
TxHashRLP = type + encode([nonce, gasPrice, gas, to, value, from, input, txSignatures, feePayer, feePayerSignatures])
TxHash = keccak256(TxHashRLP)
```

### Mã hóa RLP (Ví dụ) <a href="#rlp-encoding-example" id="rlp-encoding-example"></a>

Phần dưới đây cho thấy kết quả của quá trình tuần tự hóa RLP và đối tượng giao dịch:

```javascript
ChainID 0x1
PrivateKey 0x45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8
PublicKey.X 0x3a514176466fa815ed481ffad09110a2d344f6c9b78c1d14afc351c3a51be33d
PublicKey.Y 0x8072e77939dc03ba44790779b7a1025baf3003f6732430e20cd9b76d953391b3
SigRLP 0xf860b85bf859318204d219830f4240947b65b75d204abed71587c9e519a89277766ee1d00a94a94f5374fce5edbc8e2a8697c15331677e6ebf0ba46353586b000000000000000000000000bc5951f055a85f41a3b62fd6f68ab7de76d299b2018080
SigHash 0xa5dd93af9f96fa316f0ddd84f10acb2e6eb41baaec3b42f9068c38aa1618f7e1
Signature f845f84325a0253aea7d2c37160da45e84afbb45f6b3341cf1e8fc2df4ecc78f14adb512dc4fa022465b74015c2a8f8501186bb5e200e6ce44be52e9374615a7e7e21c41bc27b5
FeePayerPrivateKey 0xb9d5558443585bca6f225b935950e3f6e69f9da8a5809a83f51c3365dff53936
FeePayerPublicKey.X 0x327434d4cfc66ef8857d431419e9deebdc53a3e415edcc55382e2d417b8dd102
FeePayerPublicKey.Y 0x65fc97045707faf7b8f81ac65089d4cc71f69ad0bf1bc8559bc24f13fc284ced
SigRLPFeePayer 0xf875b85bf859318204d219830f4240947b65b75d204abed71587c9e519a89277766ee1d00a94a94f5374fce5edbc8e2a8697c15331677e6ebf0ba46353586b000000000000000000000000bc5951f055a85f41a3b62fd6f68ab7de76d299b2945a0043070275d9f6054307ee7348bd660849d90f018080
SigHashFeePayer 0xf547d9d0041912e0daa2db2b65170a9e833877cd8482f405a11b03429fcbd554
SignatureFeePayer f845f84326a0e7c51db7b922c6fa2a941c9687884c593b1b13076bdf0c473538d826bf7b9d1aa05b0de2aabb84b66db8bf52d62f3d3b71b592e3748455630f1504c20073624d80
TxHashRLP 0x31f8fb8204d219830f4240947b65b75d204abed71587c9e519a89277766ee1d00a94a94f5374fce5edbc8e2a8697c15331677e6ebf0ba46353586b000000000000000000000000bc5951f055a85f41a3b62fd6f68ab7de76d299b2f845f84325a0253aea7d2c37160da45e84afbb45f6b3341cf1e8fc2df4ecc78f14adb512dc4fa022465b74015c2a8f8501186bb5e200e6ce44be52e9374615a7e7e21c41bc27b5945a0043070275d9f6054307ee7348bd660849d90ff845f84326a0e7c51db7b922c6fa2a941c9687884c593b1b13076bdf0c473538d826bf7b9d1aa05b0de2aabb84b66db8bf52d62f3d3b71b592e3748455630f1504c20073624d80
TxHash ef46f28c54b3d90a183e26f406ca1d5cc2b6e9fbb6cfa7c85a10330ffadf54b0
SenderTxHashRLP 0x31f89f8204d219830f4240947b65b75d204abed71587c9e519a89277766ee1d00a94a94f5374fce5edbc8e2a8697c15331677e6ebf0ba46353586b000000000000000000000000bc5951f055a85f41a3b62fd6f68ab7de76d299b2f845f84325a0253aea7d2c37160da45e84afbb45f6b3341cf1e8fc2df4ecc78f14adb512dc4fa022465b74015c2a8f8501186bb5e200e6ce44be52e9374615a7e7e21c41bc27b5
SenderTxHash 3cd3380f4206943422d5d5b218dd66d03d60d19a109f9929ea12b52a230257cb

    TX(ef46f28c54b3d90a183e26f406ca1d5cc2b6e9fbb6cfa7c85a10330ffadf54b0)
    Type:          TxTypeFeeDelegatedSmartContractExecution
    From:          0xa94f5374Fce5edBC8E2a8697C15331677e6EbF0B
    To:            0x7b65B75d204aBed71587c9E519a89277766EE1d0
    Nonce:         1234
    GasPrice:      0x19
    GasLimit:      0xf4240
    Value:         0xa
    Data:          363335333538366230303030303030303030303030303030303030303030303062633539353166303535613835663431613362363266643666363861623764653736643239396232
    Signature:     [{"V":"0x25","R":"0x253aea7d2c37160da45e84afbb45f6b3341cf1e8fc2df4ecc78f14adb512dc4f","S":"0x22465b74015c2a8f8501186bb5e200e6ce44be52e9374615a7e7e21c41bc27b5"}]
    FeePayer:      0x5A0043070275d9f6054307Ee7348bD660849D90f
    FeePayerSig:   [{"V":"0x26","R":"0xe7c51db7b922c6fa2a941c9687884c593b1b13076bdf0c473538d826bf7b9d1a","S":"0x5b0de2aabb84b66db8bf52d62f3d3b71b592e3748455630f1504c20073624d80"}]
    Hex:           31f8fb8204d219830f4240947b65b75d204abed71587c9e519a89277766ee1d00a94a94f5374fce5edbc8e2a8697c15331677e6ebf0ba46353586b000000000000000000000000bc5951f055a85f41a3b62fd6f68ab7de76d299b2f845f84325a0253aea7d2c37160da45e84afbb45f6b3341cf1e8fc2df4ecc78f14adb512dc4fa022465b74015c2a8f8501186bb5e200e6ce44be52e9374615a7e7e21c41bc27b5945a0043070275d9f6054307ee7348bd660849d90ff845f84326a0e7c51db7b922c6fa2a941c9687884c593b1b13076bdf0c473538d826bf7b9d1aa05b0de2aabb84b66db8bf52d62f3d3b71b592e3748455630f1504c20073624d80
```

### Kết quả đầu ra RPC (Example) <a href="#rpc-output-example" id="rpc-output-example"></a>

Phần dưới đây cho thấy một đối tượng giao dịch được trả về qua JSON RPC.

```javascript
{
  "blockHash": "0x82983fe294d286e76486760e6904369285554e1744af16786c2393a956fb4ec4",
  "blockNumber": "0x2",
  "contractAddress": null,
  "feePayer": "0x029fdce0457db02f05c4be9f67b7115cb8ea15ca",
  "feePayerSignatures": [
    {
      "V": "0x25",
      "R": "0x1c7de2c83542b623ba47722f310c0e5893486eef4eed70b634d456262fb430a7",
      "S": "0x177929c52669c4b9433565a76e53723b702bae8142debe1981062f59f25062ab"
    }
  ],
  "from": "0x0fcda0f2efbe1b4e61b487701ce4f2f8abc3723d",
  "gas": "0x174876e800",
  "gasPrice": "0x0",
  "gasUsed": "0xb0bc",
  "input": "0x6353586b0000000000000000000000000fcda0f2efbe1b4e61b487701ce4f2f8abc3723d",
  "nhật ký": [],
  "nhật kýBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
  "nonce": "0xe",
  "senderTxHash": "0xffd354e4e271ff94a7459c2f1bc0df20dc112a83f5625ff7e31d196444f72710",
  "signatures": [
    {
      "V": "0x25",
      "R": "0xefc6fec3dae47a08941712f637c95dbc46ef2afd3d16e68da602a878c0bba047",
      "S": "0x938a5374edcea0503df8e7af906a7642f7e935eab7c489b7ca8b976a8e5ab7e"
    }
  ],
  "trạng thái": "0x1",
  "to": "0x636f6e74726163742e6b6c6179746e0000000000",
  "transactionHash": "0x658a118112ffb0c06adecd59b0f11b58cf7d8afd7ec5e5d323cfca021c3dcb37",
  "transactionIndex": "0x7",
  "type": "TxTypeFeeDelegatedSmartContractExecution",
  "typeInt": 49,
  "value": "0xa"
}
```

## TxTypeFeeDelegatedAccountUpdate <a href="#txtypefeedelegatedaccountupdate" id="txtypefeedelegatedaccountupdate"></a>

TxTypeFeeDelegatedAccountUpdate cập nhật khóa của tài khoản đã cho. Phí giao dịch do người trả phí thanh toán. Các thay đổi sau sẽ diễn ra nhờ loại giao dịch này.

1. Số dư của người trả phí giảm đi một lượng bằng khoản phí giao dịch.
2. Số dùng một lần của người gửi tăng thêm một đơn vị.
3. Khóa tài khoản được cập nhật bằng `key`.
4. Khi loại giao dịch này đã được triển khai, các giao dịch gửi từ tài khoản này từ đó sẽ được xác thực bằng `key` mới.
5. Phí giao dịch do người trả phí thanh toán.

### Thuộc tính <a href="#attributes" id="attributes"></a>

| Thuộc tính         | Loại                                     | Mô tả                                                                                                                                                                                                                                                                                                                                                |
| ------------------ | ----------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| type               | uint8 (Go)                                | Loại TxTypeAccountUpdate. Thuộc tính này phải là 0x21.                                                                                                                                                                                                                                                                                               |
| nonce              | uint64 (Go)                               | Giá trị dùng để định danh duy nhất cho một giao dịch của người gửi. Nếu hai giao dịch có cùng một giá trị số dùng một lần do người gửi tạo ra, chỉ có một giao dịch sẽ được thực thi.                                                                                                                                                                |
| giá gas            | \*big.Int (Go)                            | Hệ số nhân để tính toán số lượng token mà người gửi sẽ thanh toán. Lượng token mà người gửi sẽ thanh toán được tính theo công thức `gas` \* `gasPrice`. Ví dụ: Người gửi sẽ thanh toán khoản phí giao dịch là 10 KLAY nếu gas bằng 10 và gasPrice là 10^18. Hãy xem [Đơn vị của KLAY](/content/klaytn/design/klaytn-native-coin-klay#units-of-klay). |
| gas                | uint64 (Go)                               | Giá trị phí giao dịch tối đa mà giao dịch được phép sử dụng.                                                                                                                                                                                                                                                                                         |
| từ                 | common.Address (Go)                       | Địa chỉ của người gửi. Để biết thêm chi tiết, hãy xem [Xác thực chữ ký của giao dịch](/content/klaytn/design/transactions#signature-validation-of-transactions).                                                                                                                                                                                     |
| khóa               | AccountKey (Go)                           | \[AccountKey]\[] cần cập nhật cho tài khoản.                                                                                                                                                                                                                                                                                                         |
| txSignatures       | \[]{\*big.Int, \*big.Int, \*big.Int} (Go) | Chữ ký của người gửi. Để biết thêm chi tiết, hãy xem [Xác thực chữ ký của giao dịch](/content/klaytn/design/transactions#signature-validation-of-transactions).                                                                                                                                                                                      |
| feePayer           | common.Address (Go)                       | Địa chỉ của người trả phí.                                                                                                                                                                                                                                                                                                                           |
| feePayerSignatures | \[]{\*big.Int, \*big.Int, \*big.Int} (Go) | Chữ ký của người trả phí.                                                                                                                                                                                                                                                                                                                            |

### Mã hóa RLP cho chữ ký của người gửi <a href="#rlp-encoding-for-signature-of-the-sender" id="rlp-encoding-for-signature-of-the-sender"></a>

Để tạo chữ ký của người gửi, quá trình tuần tự hóa RLP phải diễn ra như sau:

```javascript
SigRLP = encode([encode([type, nonce, gasPrice, gas, from, rlpEncodedKey]), chainid, 0, 0])`
SigHash = keccak256(SigRLP)
Signature = sign(SigHash, <the sender's private key>)
```

### Mã hóa RLP cho chữ ký của người trả phí <a href="#rlp-encoding-for-signature-of-the-fee-payer" id="rlp-encoding-for-signature-of-the-fee-payer"></a>

Để tạo chữ ký của người trả phí, quá trình tuần tự hóa RLP phải diễn ra như sau:

```javascript
SigFeePayerRLP = encode([encode([type, nonce, gasPrice, gas, from, rlpEncodedKey]), feePayer, chainid, 0, 0])
SigFeePayerHash = keccak256(SigFeePayerRLP)
SignatureFeePayer = sign(SigFeePayerHash, <the fee payer's private key>)
```

### Mã hóa RLP cho SenderTxHash <a href="#rlp-encoding-for-sendertxhash" id="rlp-encoding-for-sendertxhash"></a>

Để tạo một SenderTxHash, quá trình tuần tự hóa RLP phải diễn ra như sau:

```javascript
txSignatures (a single signature) = [[v, r, s]]
txSignatures (two signatures) = [[v1, r1, s1], [v2, r2, s2]]
SenderTxHashRLP = type + encode([nonce, gasPrice, gas, from, rlpEncodedKey, txSignatures])
SenderTxHash = keccak256(SenderTxHashRLP)
```

### Mã hóa RLP cho hàm băm giao dịch <a href="#rlp-encoding-for-transaction-hash" id="rlp-encoding-for-transaction-hash"></a>

Để tạo một hàm băm giao dịch, quá trình tuần tự hóa RLP phải diễn ra như sau:

```javascript
txSignatures (a single signature) = [[v, r, s]]
txSignatures (two signatures) = [[v1, r1, s1], [v2, r2, s2]]
feePayerSignatures (a single signature) = [[v, r, s]]
feePayerSignatures (two signatures) = [[v1, r1, s1], [v2, r2, s2]]
TxHashRLP = type + encode([nonce, gasPrice, gas, from, rlpEncodedKey, txSignatures, feePayer, feePayerSignatures])
TxHash = keccak256(TxHashRLP)
```

### Mã hóa RLP (Ví dụ) <a href="#rlp-encoding-example" id="rlp-encoding-example"></a>

Phần dưới đây cho thấy kết quả của quá trình tuần tự hóa RLP và đối tượng giao dịch:

```javascript
ChainID 0x1
PrivateKey 0x45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8
PublicKey.X 0x3a514176466fa815ed481ffad09110a2d344f6c9b78c1d14afc351c3a51be33d
PublicKey.Y 0x8072e77939dc03ba44790779b7a1025baf3003f6732430e20cd9b76d953391b3
SigRLP 0xf849b844f842218204d219830f424094a94f5374fce5edbc8e2a8697c15331677e6ebf0ba302a1033a514176466fa815ed481ffad09110a2d344f6c9b78c1d14afc351c3a51be33d018080
SigHash 0x78437953e6beb985ea3ccbee8d6a648a09d11249389477a32c7094fc7b8765ef
Signature f845f84326a0ab69d9adca15d9763c4ce6f98b35256717c6e932007658f19c5a255de9e70ddaa026aa676a3a1a6e96aff4a3df2335788d614d54fb4db1c3c48551ce1fa7ac5e52
FeePayerPrivateKey 0xb9d5558443585bca6f225b935950e3f6e69f9da8a5809a83f51c3365dff53936
FeePayerPublicKey.X 0x327434d4cfc66ef8857d431419e9deebdc53a3e415edcc55382e2d417b8dd102
FeePayerPublicKey.Y 0x65fc97045707faf7b8f81ac65089d4cc71f69ad0bf1bc8559bc24f13fc284ced
SigRLPFeePayer 0xf85eb844f842218204d219830f424094a94f5374fce5edbc8e2a8697c15331677e6ebf0ba302a1033a514176466fa815ed481ffad09110a2d344f6c9b78c1d14afc351c3a51be33d945a0043070275d9f6054307ee7348bd660849d90f018080
SigHashFeePayer 0x1026d3ac74f56b52453d656b084d06798479b8bcfda1868d8beaa23e36f3aeb3
SignatureFeePayer f845f84326a0f295cd69b4144d9dbc906ba144933d2cc535d9d559f7a92b4672cc5485bf3a60a0784b8060234ffd64739b5fc2f2503939340ab4248feaa6efcf62cb874345fe40
TxHashRLP 0x21f8e48204d219830f424094a94f5374fce5edbc8e2a8697c15331677e6ebf0ba302a1033a514176466fa815ed481ffad09110a2d344f6c9b78c1d14afc351c3a51be33df845f84326a0ab69d9adca15d9763c4ce6f98b35256717c6e932007658f19c5a255de9e70ddaa026aa676a3a1a6e96aff4a3df2335788d614d54fb4db1c3c48551ce1fa7ac5e52945a0043070275d9f6054307ee7348bd660849d90ff845f84326a0f295cd69b4144d9dbc906ba144933d2cc535d9d559f7a92b4672cc5485bf3a60a0784b8060234ffd64739b5fc2f2503939340ab4248feaa6efcf62cb874345fe40
TxHash 756ff5d3912a4089659614d42a218eee59e602a5992bddca383c2d295c6637bb
SenderTxHashRLP 0x21f8888204d219830f424094a94f5374fce5edbc8e2a8697c15331677e6ebf0ba302a1033a514176466fa815ed481ffad09110a2d344f6c9b78c1d14afc351c3a51be33df845f84326a0ab69d9adca15d9763c4ce6f98b35256717c6e932007658f19c5a255de9e70ddaa026aa676a3a1a6e96aff4a3df2335788d614d54fb4db1c3c48551ce1fa7ac5e52
SenderTxHash f56937017bd3b75c637ba5b4ce90df20c166006a2a529b42e808bc806159b98f

    TX(756ff5d3912a4089659614d42a218eee59e602a5992bddca383c2d295c6637bb)
    Type:          TxTypeFeeDelegatedAccountUpdate
    From:          0xa94f5374Fce5edBC8E2a8697C15331677e6EbF0B
    Nonce:         1234
    GasPrice:      0x19
    GasLimit:      0xf4240
    Key:           AccountKeyPublic: S256Pubkey:{"x":"0x3a514176466fa815ed481ffad09110a2d344f6c9b78c1d14afc351c3a51be33d","y":"0x8072e77939dc03ba44790779b7a1025baf3003f6732430e20cd9b76d953391b3"}
    Signature:     [{"V":"0x26","R":"0xab69d9adca15d9763c4ce6f98b35256717c6e932007658f19c5a255de9e70dda","S":"0x26aa676a3a1a6e96aff4a3df2335788d614d54fb4db1c3c48551ce1fa7ac5e52"}]
    FeePayer:      0x5A0043070275d9f6054307Ee7348bD660849D90f
    FeePayerSig:   [{"V":"0x26","R":"0xf295cd69b4144d9dbc906ba144933d2cc535d9d559f7a92b4672cc5485bf3a60","S":"0x784b8060234ffd64739b5fc2f2503939340ab4248feaa6efcf62cb874345fe40"}]
    Hex:           21f8e48204d219830f424094a94f5374fce5edbc8e2a8697c15331677e6ebf0ba302a1033a514176466fa815ed481ffad09110a2d344f6c9b78c1d14afc351c3a51be33df845f84326a0ab69d9adca15d9763c4ce6f98b35256717c6e932007658f19c5a255de9e70ddaa026aa676a3a1a6e96aff4a3df2335788d614d54fb4db1c3c48551ce1fa7ac5e52945a0043070275d9f6054307ee7348bd660849d90ff845f84326a0f295cd69b4144d9dbc906ba144933d2cc535d9d559f7a92b4672cc5485bf3a60a0784b8060234ffd64739b5fc2f2503939340ab4248feaa6efcf62cb874345fe40
```

### Kết quả đầu ra RPC (Example) <a href="#rpc-output-example" id="rpc-output-example"></a>

Phần dưới đây cho thấy một đối tượng giao dịch được trả về qua JSON RPC.

```javascript
{
  "blockHash": "0x82983fe294d286e76486760e6904369285554e1744af16786c2393a956fb4ec4",
  "blockNumber": "0x2",
  "contractAddress": null,
  "feePayer": "0x0fcda0f2efbe1b4e61b487701ce4f2f8abc3723d",
  "feePayerSignatures": [
    {
      "V": "0x25",
      "R": "0x3b019642e5ae37f3ecbf85e6fc1ee77e51d1618299367bcedd816d0da6afb1e0",
      "S": "0x5c12c87811a74183f8b56b707fa90a916b1c641652c93e52300f5cee36141d73"
    }
  ],
  "from": "0x636f6c696e322e6b6c6179746e00000000000000",
  "gas": "0x174876e800",
  "gasPrice": "0x5d21dba00",
  "gasUsed": "0xc738",
  "key": "0x02a1034ef27ba4b7d1ae09b166744c5b7ee4a7a0cc5c76b2e5d74523a0a4fb56db3191",
  "nhật ký": [],
  "nhật kýBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
  "nonce": "0x0",
  "senderTxHash": "0xf4e7ef082451d4a3c8ad7c4348fc99c965a9c130bfc98d7971f3103e3dcfda3c",
  "signatures": [
    {
      "V": "0x26",
      "R": "0xd4cb16abcdf92969dc45efacaa5827ad55738fbda08a3dbaf0f0553643084a6",
      "S": "0x23f8055933b416cf15568a017e0a11e0a5c0a8f65477f6ec71de0bf837f4a681"
    }
  ],
  "trạng thái": "0x1",
  "transactionHash": "0xeb0c14d903db38deee116ac8a0d620e6ca6aa79e4f91393abbddfa30810b9d43",
  "transactionIndex": "0x2",
  "type": "TxTypeFeeDelegatedAccountUpdate",
  "typeInt": 33
},
```

## TxTypeFeeDelegatedCancel <a href="#txtypefeedelegatedcancel" id="txtypefeedelegatedcancel"></a>

TxTypeFeeDelegatedCancel hủy bỏ việc thực thi giao dịch có cùng số dùng một lần trong bể giao dịch. Để biết thêm chi tiết, hãy xem [TxTypeCancel](/content/klaytn/design/transactions/basic#txtypecancel).

Các thay đổi sau sẽ được áp dụng nhờ loại giao dịch này. 1. Số dư của người trả phí giảm đi một lượng bằng khoản phí giao dịch. 2. Số dùng một lần của người gửi tăng thêm một đơn vị.

### Thuộc tính <a href="#attributes" id="attributes"></a>

| Thuộc tính         | type                                      | Mô tả                                                                                                                                                                                                                                                                                                                                    |
| ------------------ | ----------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| type               | uint8 (Go)                                | Loại TxTypeCancel. Thuộc tính này phải là 0x39.                                                                                                                                                                                                                                                                                          |
| nonce              | uint64 (Go)                               | Giá trị dùng để định danh duy nhất cho một giao dịch của người gửi. Nếu hai giao dịch có cùng một giá trị số dùng một lần do người gửi tạo ra, chỉ có một giao dịch sẽ được thực thi.                                                                                                                                                    |
| giá gas            | \*big.Int (Go)                            | Đơn giá của gas tính bằng `peb` mà người gửi sẽ dùng để thanh toán phí giao dịch. Số tiền phí giao dịch được tính theo công thức `gas` \* `gasPrice`. Ví dụ: Nếu giao dịch tốn 10 đơn vị gas và gasPrice là 10^18, phí giao dịch sẽ là 10 KLAY. Hãy xem [Đơn vị của KLAY](/content/klaytn/design/klaytn-native-coin-klay#units-of-klay). |
| gas                | uint64 (Go)                               | Giá trị phí giao dịch tối đa mà giao dịch được phép sử dụng.                                                                                                                                                                                                                                                                             |
| từ                 | common.Address (Go)                       | Địa chỉ của người gửi. Để biết thêm chi tiết, hãy xem [Xác thực chữ ký của giao dịch](/content/klaytn/design/transactions#signature-validation-of-transactions).                                                                                                                                                                         |
| txSignatures       | \[]{\*big.Int, \*big.Int, \*big.Int} (Go) | Chữ ký của người gửi. Để biết thêm chi tiết, hãy xem [Xác thực chữ ký của giao dịch](/content/klaytn/design/transactions#signature-validation-of-transactions).                                                                                                                                                                          |
| feePayer           | common.Address (Go)                       | Địa chỉ của người trả phí.                                                                                                                                                                                                                                                                                                               |
| feePayerSignatures | \[]{\*big.Int, \*big.Int, \*big.Int} (Go) | Chữ ký của người trả phí.                                                                                                                                                                                                                                                                                                                |

### Mã hóa RLP cho chữ ký của người gửi <a href="#rlp-encoding-for-signature-of-the-sender" id="rlp-encoding-for-signature-of-the-sender"></a>

Để tạo chữ ký của người gửi, quá trình tuần tự hóa RLP phải diễn ra như sau:

```javascript
SigRLP = encode([encode([type, nonce, gasPrice, gas, from]), chainid, 0, 0])
SigHash = keccak256(SigRLP)
Signature = sign(SigHash, <the sender's private key>)
```

### Mã hóa RLP cho chữ ký của người trả phí <a href="#rlp-encoding-for-signature-of-the-fee-payer" id="rlp-encoding-for-signature-of-the-fee-payer"></a>

Để tạo chữ ký của người trả phí, quá trình tuần tự hóa RLP phải diễn ra như sau:

```javascript
SigFeePayerRLP = encode([encode([type, nonce, gasPrice, gas, from]), feePayer, chainid, 0, 0])
SigFeePayerHash = keccak256(SigFeePayerRLP)
SignatureFeePayer = sign(SigFeePayerHash, <the fee payer's private key>)
```

### Mã hóa RLP cho SenderTxHash <a href="#rlp-encoding-for-sendertxhash" id="rlp-encoding-for-sendertxhash"></a>

Để tạo một SenderTxHash, quá trình tuần tự hóa RLP phải diễn ra như sau:

```javascript
txSignatures (a single signature) = [[v, r, s]]
txSignatures (two signatures) = [[v1, r1, s1], [v2, r2, s2]]
SenderTxHashRLP = type + encode([nonce, gasPrice, gas, from, txSignatures])
SenderTxHash = keccak256(SenderTxHashRLP)
```

### Mã hóa RLP cho hàm băm giao dịch <a href="#rlp-encoding-for-transaction-hash" id="rlp-encoding-for-transaction-hash"></a>

Để tạo một hàm băm giao dịch, quá trình tuần tự hóa RLP phải diễn ra như sau:

```javascript
txSignatures (a single signature) = [[v, r, s]]
txSignatures (two signatures) = [[v1, r1, s1], [v2, r2, s2]]
feePayerSignatures (a single signature) = [[v, r, s]]
feePayerSignatures (two signatures) = [[v1, r1, s1], [v2, r2, s2]]
TxHashRLP = type + encode([nonce, gasPrice, gas, from, txSignatures, feePayer, feePayerSignatures])
TxHash = keccak256(TxHashRLP)
```

### Mã hóa RLP (Ví dụ) <a href="#rlp-encoding-example" id="rlp-encoding-example"></a>

Phần dưới đây cho thấy kết quả của quá trình tuần tự hóa RLP và đối tượng giao dịch:

```javascript
ChainID 0x1
PrivateKey 0x45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8
PublicKey.X 0x3a514176466fa815ed481ffad09110a2d344f6c9b78c1d14afc351c3a51be33d
PublicKey.Y 0x8072e77939dc03ba44790779b7a1025baf3003f6732430e20cd9b76d953391b3
SigRLP 0xe39fde398204d219830f424094a94f5374fce5edbc8e2a8697c15331677e6ebf0b018080
SigHash 0xd36c4277f4aa1d483a5fc4d656aeea50416c28adddb27a234d320290bd2a343c
Signature f845f84326a08409f5441d4725f90905ad87f03793857d124de7a43169bc67320cd2f020efa9a060af63e87bdc565d7f7de906916b2334336ee7b24d9a71c9521a67df02e7ec92
FeePayerPrivateKey 0xb9d5558443585bca6f225b935950e3f6e69f9da8a5809a83f51c3365dff53936
FeePayerPublicKey.X 0x327434d4cfc66ef8857d431419e9deebdc53a3e415edcc55382e2d417b8dd102
FeePayerPublicKey.Y 0x65fc97045707faf7b8f81ac65089d4cc71f69ad0bf1bc8559bc24f13fc284ced
SigRLPFeePayer 0xf8389fde398204d219830f424094a94f5374fce5edbc8e2a8697c15331677e6ebf0b945a0043070275d9f6054307ee7348bd660849d90f018080
SigHashFeePayer 0x15859ecc06acbd2dd5820c5968a85590826d1f6affb938e89559558ac4f86a24
SignatureFeePayer f845f84326a0044d5b25e8c649a1fdaa409dc3817be390ad90a17c25bc17c89b6d5d248495e0a073938e690d27b5267c73108352cf12d01de7fd0077b388e94721aa1fa32f85ec
TxHashRLP 0x39f8c08204d219830f424094a94f5374fce5edbc8e2a8697c15331677e6ebf0bf845f84326a08409f5441d4725f90905ad87f03793857d124de7a43169bc67320cd2f020efa9a060af63e87bdc565d7f7de906916b2334336ee7b24d9a71c9521a67df02e7ec92945a0043070275d9f6054307ee7348bd660849d90ff845f84326a0044d5b25e8c649a1fdaa409dc3817be390ad90a17c25bc17c89b6d5d248495e0a073938e690d27b5267c73108352cf12d01de7fd0077b388e94721aa1fa32f85ec
TxHash 96b39d3ab849127d31a5f7b5c882ca9ba408cd9d875052640d51a64f8c4acbb2
SenderTxHashRLP 0x39f8648204d219830f424094a94f5374fce5edbc8e2a8697c15331677e6ebf0bf845f84326a08409f5441d4725f90905ad87f03793857d124de7a43169bc67320cd2f020efa9a060af63e87bdc565d7f7de906916b2334336ee7b24d9a71c9521a67df02e7ec92
SenderTxHash cc6c2673398903b3d906a3023b41636fc08bd1bddd5aa1602116091638f48447

    TX(96b39d3ab849127d31a5f7b5c882ca9ba408cd9d875052640d51a64f8c4acbb2)
    Type:          TxTypeFeeDelegatedCancel
    From:          0xa94f5374Fce5edBC8E2a8697C15331677e6EbF0B
    Nonce:         1234
    GasPrice:      0x19
    GasLimit:      0xf4240
    Signature:     [{"V":"0x26","R":"0x8409f5441d4725f90905ad87f03793857d124de7a43169bc67320cd2f020efa9","S":"0x60af63e87bdc565d7f7de906916b2334336ee7b24d9a71c9521a67df02e7ec92"}]
    FeePayer:      0x5A0043070275d9f6054307Ee7348bD660849D90f
    FeePayerSig:   [{"V":"0x26","R":"0x44d5b25e8c649a1fdaa409dc3817be390ad90a17c25bc17c89b6d5d248495e0","S":"0x73938e690d27b5267c73108352cf12d01de7fd0077b388e94721aa1fa32f85ec"}]
    Hex:           39f8c08204d219830f424094a94f5374fce5edbc8e2a8697c15331677e6ebf0bf845f84326a08409f5441d4725f90905ad87f03793857d124de7a43169bc67320cd2f020efa9a060af63e87bdc565d7f7de906916b2334336ee7b24d9a71c9521a67df02e7ec92945a0043070275d9f6054307ee7348bd660849d90ff845f84326a0044d5b25e8c649a1fdaa409dc3817be390ad90a17c25bc17c89b6d5d248495e0a073938e690d27b5267c73108352cf12d01de7fd0077b388e94721aa1fa32f85ec
```

### Kết quả đầu ra RPC (Example) <a href="#rpc-output-example" id="rpc-output-example"></a>

Phần dưới đây cho thấy một đối tượng giao dịch được trả về qua JSON RPC.

```javascript
{
  "blockHash": "0x82983fe294d286e76486760e6904369285554e1744af16786c2393a956fb4ec4",
  "blockNumber": "0x2",
  "contractAddress": null,
  "feePayer": "0x029fdce0457db02f05c4be9f67b7115cb8ea15ca",
  "feePayerSignatures": [
    {
      "V": "0x25",
      "R": "0x26a7c88e1fc77400f2a4c7911966a5e51b0873e3f26daf9d6519b93e3f3db6a3",
      "S": "0x560e5fa8d53ebf899eb48353bf14794c76784240a6a212f5ddbe7f1684088f3f"
    }
  ],
  "from": "0x0fcda0f2efbe1b4e61b487701ce4f2f8abc3723d",
  "gas": "0x174876e800",
  "gasPrice": "0x5d21dba00",
  "gasUsed": "0x7918",
  "nhật ký": [],
  "nhật kýBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
  "nonce": "0x11",
  "senderTxHash": "0x2fea0ff37b8b936d4c06f29b98c4bd200827423fb445f931eb64725aefcda053",
  "signatures": [
    {
      "V": "0x26",
      "R": "0xcfdb5b3ff6c87a8f18ae606b371d1e569c56d35a737831b89052c5a8ef19d049",
      "S": "0x1ee63bd5a01c45d0c6f1b36a29e1c01b56baa719f008c556bc9054ac5a64bd8d"
    }
  ],
  "trạng thái": "0x1",
  "transactionHash": "0xf475e714b30aef0b79d46c9482289f3fbe51f1e44bcbc99a90ac8e25672bc969",
  "transactionIndex": "0xa",
  "type": "TxTypeFeeDelegatedCancel",
  "typeInt": 57
}
```

## TxTypeFeeDelegatedChainDataAnchoring <a href="#txtypefeedelegatedchaindataanchoring" id="txtypefeedelegatedchaindataanchoring"></a>

TxTypeFeeDelegatedChainDataAnchoring là một giao dịch có phí ủy thác neo dữ liệu chuỗi dịch vụ vào chuỗi chính của Klaytn. Các chuỗi dịch vụ gửi định kỳ loại giao dịch này đến chuỗi chính Klaytn để đảm bảo tính bảo mật và độ tin cậy của dữ liệu. Để biết thêm chi tiết về việc neo dữ liệu, hãy xem [Neo](/content/installation-guide/deployment/service-chain/references/anchoring). Vì đây cũng là một giao dịch có phí ủy thác nên phí giao dịch cũng được tính cho người trả phí. Lưu ý rằng giao dịch này không được phép gửi qua RPC. Hiện tại, giao dịch này được thực thi qua các kênh p2p riêng tư vì lý do bảo mật. Giao dịch này không làm thay đổi trạng thái của chuỗi khối Klaytn, ngoại trừ việc số dùng một lần của người gửi tăng lên một đơn vị.

### Thuộc tính <a href="#attributes" id="attributes"></a>

| Thuộc tính         | Loại                                     | Mô tả                                                                                                                                                                                                                                                                                                                                    |
| ------------------ | ----------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| type               | uint8 (Go)                                | Loại TxTypeFeeDelegatedChainDataAnchoring. Thuộc tính này phải là 0x49.                                                                                                                                                                                                                                                                  |
| nonce              | uint64 (Go)                               | Giá trị dùng để định danh duy nhất cho một giao dịch của người gửi. Nếu hai giao dịch có cùng một giá trị số dùng một lần do người gửi tạo ra, chỉ có một giao dịch sẽ được thực thi.                                                                                                                                                    |
| giá gas            | \*big.Int (Go)                            | Đơn giá của gas tính bằng `peb` mà người gửi sẽ dùng để thanh toán phí giao dịch. Số tiền phí giao dịch được tính theo công thức `gas` \* `gasPrice`. Ví dụ: Nếu giao dịch tốn 10 đơn vị gas và gasPrice là 10^18, phí giao dịch sẽ là 10 KLAY. Hãy xem [Đơn vị của KLAY](/content/klaytn/design/klaytn-native-coin-klay#units-of-klay). |
| gas                | uint64 (Go)                               | Giá trị phí giao dịch tối đa mà giao dịch được phép sử dụng.                                                                                                                                                                                                                                                                             |
| từ                 | common.Address (Go)                       | Địa chỉ của người gửi. Để biết thêm chi tiết, hãy xem [Xác thực chữ ký của giao dịch](/content/klaytn/design/transactions#signature-validation-of-transactions).                                                                                                                                                                         |
| nhập               | \[]byte (Go)                              | Dữ liệu của chuỗi dịch vụ.                                                                                                                                                                                                                                                                                                               |
| txSignatures       | \[]{\*big.Int, \*big.Int, \*big.Int} (Go) | Chữ ký của người gửi. Để biết thêm chi tiết, hãy xem [Xác thực chữ ký của giao dịch](/content/klaytn/design/transactions#signature-validation-of-transactions).                                                                                                                                                                          |
| feePayer           | common.Address (Go)                       | Địa chỉ của người trả phí.                                                                                                                                                                                                                                                                                                               |
| feePayerSignatures | \[]{\*big.Int, \*big.Int, \*big.Int} (Go) | Chữ ký của người trả phí.                                                                                                                                                                                                                                                                                                                |

### Mã hóa RLP cho chữ ký của người gửi <a href="#rlp-encoding-for-signature-of-the-sender" id="rlp-encoding-for-signature-of-the-sender"></a>

Để tạo chữ ký của người gửi, quá trình tuần tự hóa RLP phải diễn ra như sau:

```javascript
SigRLP = encode([encode([type, nonce, gasPrice, gas, from, anchoredData]), chainid, 0, 0])
SigHash = keccak256(SigRLP)
Signature = sign(SigHash, <private key>)
```

### Mã hóa RLP cho chữ ký của người trả phí <a href="#rlp-encoding-for-signature-of-the-fee-payer" id="rlp-encoding-for-signature-of-the-fee-payer"></a>

Để tạo chữ ký của người trả phí, quá trình tuần tự hóa RLP phải diễn ra như sau:

```javascript
SigFeePayerRLP = encode([encode([type, nonce, gasPrice, gas, from, anchoredData]), feePayer, chainid, 0, 0])
SigFeePayerHash = keccak256(SigFeePayerRLP)
SignatureFeePayer = sign(SigFeePayerHash, <the fee payer's private key>)
```

### Mã hóa RLP cho SenderTxHash <a href="#rlp-encoding-for-sendertxhash" id="rlp-encoding-for-sendertxhash"></a>

Để tạo một SenderTxHash, quá trình tuần tự hóa RLP phải diễn ra như sau:

```javascript
txSignatures (a single signature) = [[v, r, s]]
txSignatures (two signatures) = [[v1, r1, s1], [v2, r2, s2]]
SenderTxHashRLP = type + encode([nonce, gasPrice, gas, from, anchoredData, txSignatures])
SenderTxHash = keccak256(SenderTxHashRLP)
```

### Mã hóa RLP cho hàm băm giao dịch <a href="#rlp-encoding-for-transaction-hash" id="rlp-encoding-for-transaction-hash"></a>

Để tạo một hàm băm giao dịch, quá trình tuần tự hóa RLP phải diễn ra như sau:

```javascript
txSignatures (a single signature) = [[v, r, s]]
txSignatures (two signatures) = [[v1, r1, s1], [v2, r2, s2]]
feePayerSignatures (a single signature) = [[v, r, s]]
feePayerSignatures (two signatures) = [[v1, r1, s1], [v2, r2, s2]]
TxHashRLP = type + encode([nonce, gasPrice, gas, from, anchoredData, txSignatures, feePayer, feePayerSignatures])
TxHash = keccak256(TxHashRLP)
```

### Mã hóa RLP (Ví dụ) <a href="#rlp-encoding-example" id="rlp-encoding-example"></a>

Phần dưới đây cho thấy kết quả của quá trình tuần tự hóa RLP và đối tượng giao dịch:

```javascript
ChainID 0x01
PrivateKey 0x45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8
PublicKey.X 0x3a514176466fa815ed481ffad09110a2d344f6c9b78c1d14afc351c3a51be33d
PublicKey.Y 0x8072e77939dc03ba44790779b7a1025baf3003f6732430e20cd9b76d953391b3
SigRLP 0xf8dbb8d6f8d449118505d21dba0085174876e80094a94f5374fce5edbc8e2a8697c15331677e6ebf0bb8aff8ad80b8aaf8a8a00000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000001a00000000000000000000000000000000000000000000000000000000000000002a00000000000000000000000000000000000000000000000000000000000000003a00000000000000000000000000000000000000000000000000000000000000004058006018080
SigHash 0x92e385b4a162170ee87b2b2e598f686b1d16f385d98ad626147305624abec0b3
Signature 0xf845f84326a0afe41edc9cce1185ab9065ca7dbfb89ab5c7bde3602a659aa258324124644142a0317848698248ba7cc057b8f0dd19a27b52ef904d29cb72823100f1ed18ba2bb3
FeePayerPublicKey.X 0x327434d4cfc66ef8857d431419e9deebdc53a3e415edcc55382e2d417b8dd102
FeePayerPublicKey.Y 0x65fc97045707faf7b8f81ac65089d4cc71f69ad0bf1bc8559bc24f13fc284ced
SigRLPFeePayer 0xf8f0b8d6f8d449118505d21dba0085174876e80094a94f5374fce5edbc8e2a8697c15331677e6ebf0bb8aff8ad80b8aaf8a8a00000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000001a00000000000000000000000000000000000000000000000000000000000000002a00000000000000000000000000000000000000000000000000000000000000003a000000000000000000000000000000000000000000000000000000000000000040580069433f524631e573329a550296f595c820d6c65213f018080
SigHashFeePayer 0x4d58fdf276fde1e221b6bab8c6621ae1639b00a7a70d2bd0a114001692a3a7d1
SignatureFeePayer 0xf845f84325a0309e46db21a1bf7bfdae24d9192aca69516d6a341ecce8971fc69cff481cee76a04b939bf7384c4f919880307323a5e36d4d6e029bae1887a43332710cdd48f174
TxHashRLP 0x49f90176118505d21dba0085174876e80094a94f5374fce5edbc8e2a8697c15331677e6ebf0bb8aff8ad80b8aaf8a8a00000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000001a00000000000000000000000000000000000000000000000000000000000000002a00000000000000000000000000000000000000000000000000000000000000003a00000000000000000000000000000000000000000000000000000000000000004058006f845f84326a0afe41edc9cce1185ab9065ca7dbfb89ab5c7bde3602a659aa258324124644142a0317848698248ba7cc057b8f0dd19a27b52ef904d29cb72823100f1ed18ba2bb39433f524631e573329a550296f595c820d6c65213ff845f84325a0309e46db21a1bf7bfdae24d9192aca69516d6a341ecce8971fc69cff481cee76a04b939bf7384c4f919880307323a5e36d4d6e029bae1887a43332710cdd48f174
TxHash 0xecf1ec12937065617f9b3cd07570452bfdb75dc36404c4f37f78995c6dc462af
SenderTxHashRLP 0x49f9011a118505d21dba0085174876e80094a94f5374fce5edbc8e2a8697c15331677e6ebf0bb8aff8ad80b8aaf8a8a00000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000001a00000000000000000000000000000000000000000000000000000000000000002a00000000000000000000000000000000000000000000000000000000000000003a00000000000000000000000000000000000000000000000000000000000000004058006f845f84326a0afe41edc9cce1185ab9065ca7dbfb89ab5c7bde3602a659aa258324124644142a0317848698248ba7cc057b8f0dd19a27b52ef904d29cb72823100f1ed18ba2bb3
SenderTxHash 0x4f5c00ea8f6346baa7d4400dfefd72efa5ec219561ebcebed7be8a2b79d52bcd

    TX(ecf1ec12937065617f9b3cd07570452bfdb75dc36404c4f37f78995c6dc462af)
    Type:          TxTypeFeeDelegatedChainDataAnchoring
    From:          0xa94f5374Fce5edBC8E2a8697C15331677e6EbF0B
    Nonce:         17
    GasPrice:      0x5d21dba00
    GasLimit:      0x174876e800
    AnchoredData:  f8ad80b8aaf8a8a00000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000001a00000000000000000000000000000000000000000000000000000000000000002a00000000000000000000000000000000000000000000000000000000000000003a00000000000000000000000000000000000000000000000000000000000000004058006
    Signature:     [{"V":"0x26","R":"0xafe41edc9cce1185ab9065ca7dbfb89ab5c7bde3602a659aa258324124644142","S":"0x317848698248ba7cc057b8f0dd19a27b52ef904d29cb72823100f1ed18ba2bb3"}]
    FeePayer:      0x33f524631e573329a550296F595c820D6c65213f
    FeePayerSig:   [{"V":"0x25","R":"0x309e46db21a1bf7bfdae24d9192aca69516d6a341ecce8971fc69cff481cee76","S":"0x4b939bf7384c4f919880307323a5e36d4d6e029bae1887a43332710cdd48f174"}]
    Hex:           49f90176118505d21dba0085174876e80094a94f5374fce5edbc8e2a8697c15331677e6ebf0bb8aff8ad80b8aaf8a8a00000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000001a00000000000000000000000000000000000000000000000000000000000000002a00000000000000000000000000000000000000000000000000000000000000003a00000000000000000000000000000000000000000000000000000000000000004058006f845f84326a0afe41edc9cce1185ab9065ca7dbfb89ab5c7bde3602a659aa258324124644142a0317848698248ba7cc057b8f0dd19a27b52ef904d29cb72823100f1ed18ba2bb39433f524631e573329a550296f595c820d6c65213ff845f84325a0309e46db21a1bf7bfdae24d9192aca69516d6a341ecce8971fc69cff481cee76a04b939bf7384c4f919880307323a5e36d4d6e029bae1887a43332710cdd48f174
```

### Kết quả đầu ra RPC (Example) <a href="#rpc-output-example" id="rpc-output-example"></a>

Phần dưới đây cho thấy một đối tượng giao dịch được trả về qua JSON RPC.

```javascript
{
    "blockHash": "0x170a32e16b6fdced144d5104f5aecf753878bd9f1a7d87ddccc2e6d2ba27354c",
    "blockNumber": "0x2",
    "contractAddress": null,
    "feePayer": "0x33f524631e573329a550296f595c820d6c65213f",
    "feePayerSignatures": [
        {
            "V": "0x25",
            "R": "0x309e46db21a1bf7bfdae24d9192aca69516d6a341ecce8971fc69cff481cee76",
            "S": "0x4b939bf7384c4f919880307323a5e36d4d6e029bae1887a43332710cdd48f174"
        }
    ],
    "from": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
    "gas": "0x174876e800",
    "gasPrice": "0x5d21dba00",
    "gasUsed": "0xbd74",
    "input": "0xf8ad80b8aaf8a8a00000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000001a00000000000000000000000000000000000000000000000000000000000000002a00000000000000000000000000000000000000000000000000000000000000003a00000000000000000000000000000000000000000000000000000000000000004058006",
    "nhật ký": [],
    "nhật kýBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
    "nonce": "0x11",
    "senderTxHash": "0x4f5c00ea8f6346baa7d4400dfefd72efa5ec219561ebcebed7be8a2b79d52bcd",
    "signatures": [
        {
            "V": "0x26",
            "R": "0xafe41edc9cce1185ab9065ca7dbfb89ab5c7bde3602a659aa258324124644142",
            "S": "0x317848698248ba7cc057b8f0dd19a27b52ef904d29cb72823100f1ed18ba2bb3"
        }
    ],
    "trạng thái": "0x1",
    "transactionHash": "0xecf1ec12937065617f9b3cd07570452bfdb75dc36404c4f37f78995c6dc462af",
    "transactionIndex": "0xa",
    "type": "TxTypeFeeDelegatedChainDataAnchoring",
    "typeInt": 73
}
```

\[AccountKey]: ../tài khoảns.md#tài khoản-key


# Ủy thác phí một phần

## TxTypeFeeDelegatedValueTransferWithRatio <a href="#txtypefeedelegatedvaluetransferwithratio" id="txtypefeedelegatedvaluetransferwithratio"></a>

TxTypeFeeDelegatedValueTransferWithRatio được sử dụng khi người dùng muốn gửi KLAY. Vì Klaytn cung cấp nhiều loại giao dịch sao cho mỗi loại giao dịch chỉ phục vụ một mục đích duy nhất, TxTypeFeeDelegatedValueTransferWithRatio bị giới hạn gửi KLAY đến một tài khoản được sở hữu bên ngoài. Vì thế, TxTypeFeeDelegatedValueTransferWithRatio chỉ được chấp nhận nếu `to` là một tài khoản thuộc sở hữu bên ngoài. Để chuyển KLAY đến một tài khoản hợp đồng thông minh, hãy dùng [TxTypeFeeDelegatedSmartContractExecutionWithRatio](#txtypefeedelegatedsmartcontractexecutionwithratio). Các thay đổi sau sẽ được tạo ra nhờ loại giao dịch này.

1. Số dư của người trả phí giảm đi một lượng bằng tỷ lệ cho trước của phí giao dịch.
2. Số dư của người gửi giảm đi một lượng bằng phần còn lại của phí giao dịch. Ví dụ: Nếu `feeRatio` là 30 thì 30% của khoản phí sẽ do người trả phí thanh toán và phần 70% còn lại của khoản phí sẽ do người gửi thanh toán.
3. Số dùng một lần của người gửi tăng thêm một đơn vị.
4. `value` KLAY sẽ được chuyển từ người gửi đến người nhận.

### Thuộc tính <a href="#attributes" id="attributes"></a>

| Thuộc tính         | type                                      | Mô tả                                                                                                                                                                                                                                                                                                                                    |
| ------------------ | ----------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| type               | uint8 (Go)                                | Loại TxTypeFeeDelegatedValueTransferWithRatio. Thuộc tính này phải là 0x0a.                                                                                                                                                                                                                                                              |
| nonce              | uint64 (Go)                               | Giá trị dùng để định danh duy nhất cho một giao dịch của người gửi. Nếu hai giao dịch có cùng một giá trị số dùng một lần do người gửi tạo ra, chỉ có một giao dịch sẽ được thực thi.                                                                                                                                                    |
| giá gas            | \*big.Int (Go)                            | Đơn giá của gas tính bằng `peb` mà người gửi sẽ dùng để thanh toán phí giao dịch. Số tiền phí giao dịch được tính theo công thức `gas` \* `gasPrice`. Ví dụ: nếu giao dịch tốn 10 đơn vị gas và gasPrice là 10^18, phí giao dịch sẽ là 10 KLAY. Hãy xem [Đơn vị của KLAY](/content/klaytn/design/klaytn-native-coin-klay#units-of-klay). |
| gas                | uint64 (Go)                               | Lượng gas tối đa mà giao dịch được phép sử dụng.                                                                                                                                                                                                                                                                                         |
| đến                | common.Address (Go)                       | Địa chỉ tài khoản sẽ nhận giá trị được chuyển.                                                                                                                                                                                                                                                                                           |
| giá trị            | \*big.Int (Go)                            | Số lượng KLAY tính bằng `peb` sẽ được chuyển.                                                                                                                                                                                                                                                                                            |
| từ                 | common.Address (Go)                       | Địa chỉ của người gửi. Để biết thêm chi tiết, hãy xem [Xác thực chữ ký của giao dịch](/content/klaytn/design/transactions#signature-validation-of-transactions).                                                                                                                                                                         |
| feeRatio           | uint8 (Go)                                | Tỷ lệ phí của người trả phí. Khoảng hợp lệ là từ 1 đến 99. Số không (0) không được chấp nhận. Số từ 100 trở lên cũng không được chấp nhận.                                                                                                                                                                                               |
| txSignatures       | \[]{\*big.Int, \*big.Int, \*big.Int} (Go) | Chữ ký của người gửi. Để biết thêm chi tiết, hãy xem [Xác thực chữ ký của giao dịch](/content/klaytn/design/transactions#signature-validation-of-transactions).                                                                                                                                                                          |
| feePayer           | common.Address (Go)                       | Địa chỉ của người trả phí.                                                                                                                                                                                                                                                                                                               |
| feePayerSignatures | \[]{\*big.Int, \*big.Int, \*big.Int} (Go) | Chữ ký của người trả phí.                                                                                                                                                                                                                                                                                                                |

### Mã hóa RLP cho chữ ký của người gửi <a href="#rlp-encoding-for-signature-of-the-sender" id="rlp-encoding-for-signature-of-the-sender"></a>

Để tạo chữ ký của người gửi, quá trình tuần tự hóa RLP phải diễn ra như sau:

```javascript
SigRLP = encode([encode([type, nonce, gasPrice, gas, to, value, from, feeRatio]), chainid, 0, 0])
SigHash = keccak256(SigRLP)
Signature = sign(SigHash, <the sender's private key>)
```

### Mã hóa RLP cho chữ ký của người trả phí <a href="#rlp-encoding-for-signature-of-the-fee-payer" id="rlp-encoding-for-signature-of-the-fee-payer"></a>

Để tạo chữ ký của người trả phí, quá trình tuần tự hóa RLP phải diễn ra như sau:

```javascript
SigFeePayerRLP = encode([encode([type, nonce, gasPrice, gas, to, value, from, feeRatio]), feePayer, chainid, 0, 0])
SigFeePayerHash = keccak256(SigFeePayerRLP)
SignatureFeePayer = sign(SigFeePayerHash, <the fee payer's private key>)
```

### Mã hóa RLP cho SenderTxHash <a href="#rlp-encoding-for-sendertxhash" id="rlp-encoding-for-sendertxhash"></a>

Để tạo một SenderTxHash, quá trình tuần tự hóa RLP phải diễn ra như sau:

```javascript
txSignatures (a single signature) = [[v, r, s]]
txSignatures (two signatures) = [[v1, r1, s1], [v2, r2, s2]]
SenderTxHashRLP = type + encode([nonce, gasPrice, gas, to, value, from, feeRatio, txSignatures])
SenderTxHash = keccak256(SenderTxHashRLP)
```

### Mã hóa RLP cho hàm băm giao dịch <a href="#rlp-encoding-for-transaction-hash" id="rlp-encoding-for-transaction-hash"></a>

Để tạo một hàm băm giao dịch, quá trình tuần tự hóa RLP phải diễn ra như sau:

```javascript
txSignatures (a single signature) = [[v, r, s]]
txSignatures (two signatures) = [[v1, r1, s1], [v2, r2, s2]]
feePayerSignatures (a single signature) = [[v, r, s]]
feePayerSignatures (two signatures) = [[v1, r1, s1], [v2, r2, s2]]
TxHashRLP = type + encode([nonce, gasPrice, gas, to, value, from, feeRatio, txSignatures, feePayer, feePayerSignatures])
TxHash = keccak256(TxHashRLP)
```

### Mã hóa RLP (Ví dụ) <a href="#rlp-encoding-example" id="rlp-encoding-example"></a>

Phần dưới đây cho thấy kết quả của quá trình tuần tự hóa RLP và đối tượng giao dịch:

```javascript
ChainID 0x1
PrivateKey 0x45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8
PublicKey.X 0x3a514176466fa815ed481ffad09110a2d344f6c9b78c1d14afc351c3a51be33d
PublicKey.Y 0x8072e77939dc03ba44790779b7a1025baf3003f6732430e20cd9b76d953391b3
SigRLP 0xf83ab6f50a8204d219830f4240947b65b75d204abed71587c9e519a89277766ee1d00a94a94f5374fce5edbc8e2a8697c15331677e6ebf0b1e018080
SigHash 0x0f7d520cd00034299b36004c21b571263dbb9a77edbd5920c4136f7f74050d9d
Signature f845f84325a0dde32b8241f039a82b124fe94d3e556eb08f0d6f26d07dcc0f3fca621f1090caa01c8c336b358ab6d3a2bbf25de2adab4d01b754e2fb3b9b710069177d54c1e956
FeePayerPrivateKey 0xb9d5558443585bca6f225b935950e3f6e69f9da8a5809a83f51c3365dff53936
FeePayerPublicKey.X 0x327434d4cfc66ef8857d431419e9deebdc53a3e415edcc55382e2d417b8dd102
FeePayerPublicKey.Y 0x65fc97045707faf7b8f81ac65089d4cc71f69ad0bf1bc8559bc24f13fc284ced
SigRLPFeePayer 0xf84fb6f50a8204d219830f4240947b65b75d204abed71587c9e519a89277766ee1d00a94a94f5374fce5edbc8e2a8697c15331677e6ebf0b1e945a0043070275d9f6054307ee7348bd660849d90f018080
SigHashFeePayer 0x38123c30a5f83db853e9ae4e8dd8d4f6aa6840415acffb8dbf18b2050463dec4
SignatureFeePayer f845f84326a0091ecf53f91bb97bb694f2f2443f3563ac2b646d651497774524394aae396360a044228b88f275aa1ec1bab43681d21dc7e3a676786ed1906f6841d0a1a188f88a
TxHashRLP 0x0af8d78204d219830f4240947b65b75d204abed71587c9e519a89277766ee1d00a94a94f5374fce5edbc8e2a8697c15331677e6ebf0b1ef845f84325a0dde32b8241f039a82b124fe94d3e556eb08f0d6f26d07dcc0f3fca621f1090caa01c8c336b358ab6d3a2bbf25de2adab4d01b754e2fb3b9b710069177d54c1e956945a0043070275d9f6054307ee7348bd660849d90ff845f84326a0091ecf53f91bb97bb694f2f2443f3563ac2b646d651497774524394aae396360a044228b88f275aa1ec1bab43681d21dc7e3a676786ed1906f6841d0a1a188f88a
TxHash 83a89f4debd8e9d6374b987e25132b3a4030c9cf9ace2fc6e7d1086fcea2ce40
SenderTxHashRLP 0x0af87b8204d219830f4240947b65b75d204abed71587c9e519a89277766ee1d00a94a94f5374fce5edbc8e2a8697c15331677e6ebf0b1ef845f84325a0dde32b8241f039a82b124fe94d3e556eb08f0d6f26d07dcc0f3fca621f1090caa01c8c336b358ab6d3a2bbf25de2adab4d01b754e2fb3b9b710069177d54c1e956
SenderTxHash 4711ed4023e821425968342c1d50063b6bc3176b1792b7075cfeee3656d450f6

    TX(83a89f4debd8e9d6374b987e25132b3a4030c9cf9ace2fc6e7d1086fcea2ce40)
    Type:          TxTypeFeeDelegatedValueTransferWithRatio
    From:          0xa94f5374Fce5edBC8E2a8697C15331677e6EbF0B
    To:            0x7b65B75d204aBed71587c9E519a89277766EE1d0
    Nonce:         1234
    GasPrice:      0x19
    GasLimit:      0xf4240
    Value:         0xa
    Signature:     [{"V":"0x25","R":"0xdde32b8241f039a82b124fe94d3e556eb08f0d6f26d07dcc0f3fca621f1090ca","S":"0x1c8c336b358ab6d3a2bbf25de2adab4d01b754e2fb3b9b710069177d54c1e956"}]
    FeePayer:      0x5A0043070275d9f6054307Ee7348bD660849D90f
    FeeRatio:      30
    FeePayerSig:   [{"V":"0x26","R":"0x91ecf53f91bb97bb694f2f2443f3563ac2b646d651497774524394aae396360","S":"0x44228b88f275aa1ec1bab43681d21dc7e3a676786ed1906f6841d0a1a188f88a"}]
    Hex:           0af8d78204d219830f4240947b65b75d204abed71587c9e519a89277766ee1d00a94a94f5374fce5edbc8e2a8697c15331677e6ebf0b1ef845f84325a0dde32b8241f039a82b124fe94d3e556eb08f0d6f26d07dcc0f3fca621f1090caa01c8c336b358ab6d3a2bbf25de2adab4d01b754e2fb3b9b710069177d54c1e956945a0043070275d9f6054307ee7348bd660849d90ff845f84326a0091ecf53f91bb97bb694f2f2443f3563ac2b646d651497774524394aae396360a044228b88f275aa1ec1bab43681d21dc7e3a676786ed1906f6841d0a1a188f88a
```

### Kết quả đầu ra RPC (Example) <a href="#rpc-output-example" id="rpc-output-example"></a>

Phần dưới đây cho thấy một đối tượng giao dịch được trả về qua JSON RPC.

```javascript
{
  "blockHash": "0x7ad6ed1f9955be00db8fb5452125f0e9a3c0856abb5b4cc4aed91ffc134321da",
  "blockNumber": "0x1",
  "contractAddress": null,
  "feePayer": "0x029fdce0457db02f05c4be9f67b7115cb8ea15ca",
  "feePayerSignatures": [
    {
      "V": "0x25",
      "R": "0xb8583f638efefb297922aa8b8a30cf451a30e266126d52da03ba9ead0fbb1ccd",
      "S": "0x4bc5ca3756f88d857d115b128b00babe5b3c0b089f087a0b30a9ced269e00603"
    }
  ],
  "feeRatio": "0x14",
  "from": "0x0fcda0f2efbe1b4e61b487701ce4f2f8abc3723d",
  "gas": "0x174876e800",
  "gasPrice": "0x5d21dba00",
  "gasUsed": "0x8ca0",
  "nhật ký": [],
  "nhật kýBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
  "nonce": "0x3",
  "senderTxHash": "0xac372c68d2937383d4344a2d187e70b207c76160eb407b68e08c944b919328de",
  "signatures": [
    {
      "V": "0x26",
      "R": "0x1a8d5bf583843ceba87943569a34a8a6caa18a9ab5e4cf6914d8048e607787bc",
      "S": "0x27458275c84adcb8144b4596946111f1a539643941de74f587fa69a7df98ed1b"
    }
  ],
  "trạng thái": "0x1",
  "to": "0x75c3098be5e4b63fbac05838daaee378dd48098d",
  "transactionHash": "0x670ff613022278cc2551a7e4669d8911f1658ffaa4dcc3695b14f39194a8a38c",
  "transactionIndex": "0x3",
  "type": "TxTypeFeeDelegatedValueTransferWithRatio",
  "typeInt": 10,
  "value": "0x989680"
}
```

## TxTypeFeeDelegatedValueTransferMemoWithRatio <a href="#txtypefeedelegatedvaluetransfermemowithratio" id="txtypefeedelegatedvaluetransfermemowithratio"></a>

TxTypeFeeDelegatedValueTransferMemoWithRatio được sử dụng khi người dùng muốn gửi KLAY với một tin nhắn cụ thể. TxTypeFeeDelegatedValueTransferMemoWithRatio chỉ được chấp nhận nếu `to` là một tài khoản sở hữu bên ngoài. Để chuyển KLAY đến một tài khoản hợp đồng thông minh, hãy dùng [TxTypeFeeDelegatedSmartContractExecutionWithRatio](#txtypefeedelegatedsmartcontractexecutionwithratio). Các thay đổi sau sẽ được tạo ra nhờ loại giao dịch này.

1. Số dư của người trả phí giảm đi theo tỷ lệ phí của khoản phí giao dịch.
2. Số dư của người gửi giảm đi một lượng bằng phần còn lại của phí giao dịch. Ví dụ: Nếu `feeRatio` là 30 thì 30% của khoản phí sẽ do người trả phí thanh toán và phần 70% còn lại của khoản phí sẽ do người gửi thanh toán.
3. Số dùng một lần của người gửi tăng thêm một đơn vị.
4. `value` KLAY sẽ được chuyển từ người gửi đến người nhận.

### Thuộc tính <a href="#attributes" id="attributes"></a>

| Thuộc tính         | Mô tả                                     | Loại                                                                                                                                                                                                                                                                                                                                    |
| ------------------ | ----------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| type               | uint8 (Go)                                | Loại TxTypeFeeDelegatedValueTransferMemoWithRatio. Thuộc tính này phải là 0x12.                                                                                                                                                                                                                                                          |
| nonce              | uint64 (Go)                               | Giá trị dùng để định danh duy nhất cho một giao dịch của người gửi. Nếu hai giao dịch có cùng một giá trị số dùng một lần do người gửi tạo ra, chỉ có một giao dịch sẽ được thực thi.                                                                                                                                                    |
| giá gas            | \*big.Int (Go)                            | Đơn giá của gas tính bằng `peb` mà người gửi sẽ dùng để thanh toán phí giao dịch. Số tiền phí giao dịch được tính theo công thức `gas` \* `gasPrice`. Ví dụ: Nếu giao dịch tốn 10 đơn vị gas và gasPrice là 10^18, phí giao dịch sẽ là 10 KLAY. Hãy xem [Đơn vị của KLAY](/content/klaytn/design/klaytn-native-coin-klay#units-of-klay). |
| gas                | uint64 (Go)                               | Lượng gas tối đa mà giao dịch được phép sử dụng.                                                                                                                                                                                                                                                                                         |
| đến                | common.Address (Go)                       | Địa chỉ tài khoản sẽ nhận giá trị được chuyển.                                                                                                                                                                                                                                                                                           |
| giá trị            | \*big.Int (Go)                            | Số lượng KLAY tính bằng `peb` sẽ được chuyển.                                                                                                                                                                                                                                                                                            |
| từ                 | common.Address (Go)                       | Địa chỉ của người gửi. Để biết thêm chi tiết, hãy xem [Xác thực chữ ký của giao dịch](/content/klaytn/design/transactions#signature-validation-of-transactions).                                                                                                                                                                         |
| nhập               | \[]byte (Go)                              | Dữ liệu gắn kèm theo giao dịch. Thông điệp cần được truyền vào thuộc tính này.                                                                                                                                                                                                                                                           |
| feeRatio           | uint8 (Go)                                | Tỷ lệ phí của người trả phí. Khoảng hợp lệ là từ 1 đến 99. Số không (0) không được chấp nhận. Số từ 100 trở lên cũng không được chấp nhận.                                                                                                                                                                                               |
| txSignatures       | \[]{\*big.Int, \*big.Int, \*big.Int} (Go) | Chữ ký của người gửi. Để biết thêm chi tiết, hãy xem [Xác thực chữ ký của giao dịch](/content/klaytn/design/transactions#signature-validation-of-transactions).                                                                                                                                                                          |
| feePayer           | common.Address (Go)                       | Địa chỉ của người trả phí.                                                                                                                                                                                                                                                                                                               |
| feePayerSignatures | \[]{\*big.Int, \*big.Int, \*big.Int} (Go) | Chữ ký của người trả phí.                                                                                                                                                                                                                                                                                                                |

### Mã hóa RLP cho chữ ký của người gửi <a href="#rlp-encoding-for-signature-of-the-sender" id="rlp-encoding-for-signature-of-the-sender"></a>

Để tạo chữ ký của người gửi, quá trình tuần tự hóa RLP phải diễn ra như sau:

```javascript
SigRLP = encode([encode([type, nonce, gasPrice, gas, to, value, from, input, feeRatio]), chainid, 0, 0])
SigHash = keccak256(SigRLP)
Signature = sign(SigHash, <the sender's private key>)
```

### Mã hóa RLP cho chữ ký của người trả phí <a href="#rlp-encoding-for-signature-of-the-fee-payer" id="rlp-encoding-for-signature-of-the-fee-payer"></a>

Để tạo chữ ký của người trả phí, quá trình tuần tự hóa RLP phải diễn ra như sau:

```javascript
SigFeePayerRLP = encode([encode([type, nonce, gasPrice, gas, to, value, from, input, feeRatio]), feePayer, chainid, 0, 0])
SigFeePayerHash = keccak256(SigFeePayerRLP)
SignatureFeePayer = sign(SigFeePayerHash, <the fee payer's private key>)
```

### Mã hóa RLP cho SenderTxHash <a href="#rlp-encoding-for-sendertxhash" id="rlp-encoding-for-sendertxhash"></a>

Để tạo một SenderTxHash, quá trình tuần tự hóa RLP phải diễn ra như sau:

```javascript
txSignatures (a single signature) = [[v, r, s]]
txSignatures (two signatures) = [[v1, r1, s1], [v2, r2, s2]]
SenderTxHashRLP = type + encode([nonce, gasPrice, gas, to, value, from, input, feeRatio, txSignatures])
SenderTxHash = keccak256(SenderTxHashRLP)
```

### Mã hóa RLP cho hàm băm giao dịch <a href="#rlp-encoding-for-transaction-hash" id="rlp-encoding-for-transaction-hash"></a>

Để tạo một hàm băm giao dịch, quá trình tuần tự hóa RLP phải diễn ra như sau:

```javascript
txSignatures (a single signature) = [[v, r, s]]
txSignatures (two signatures) = [[v1, r1, s1], [v2, r2, s2]]
feePayerSignatures (a single signature) = [[v, r, s]]
feePayerSignatures (two signatures) = [[v1, r1, s1], [v2, r2, s2]]
TxHashRLP = type + encode([nonce, gasPrice, gas, to, value, from, input, feeRatio, txSignatures, feePayer, feePayerSignatures])
TxHash = keccak256(TxHashRLP)
```

### Mã hóa RLP (Ví dụ) <a href="#rlp-encoding-example" id="rlp-encoding-example"></a>

Phần dưới đây cho thấy kết quả của quá trình tuần tự hóa RLP và đối tượng giao dịch:

```javascript
ChainID 0x1
PrivateKey 0x45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8
PublicKey.X 0x3a514176466fa815ed481ffad09110a2d344f6c9b78c1d14afc351c3a51be33d
PublicKey.Y 0x8072e77939dc03ba44790779b7a1025baf3003f6732430e20cd9b76d953391b3
SigRLP 0xf842b83df83b128204d219830f4240947b65b75d204abed71587c9e519a89277766ee1d00a94a94f5374fce5edbc8e2a8697c15331677e6ebf0b8568656c6c6f1e018080
SigHash 0x50eef45abe0743dce17e40db185d1d85607245a545f7517a52b90f3673aff689
Signature f845f84326a0769f0afdc310289f9b24decb5bb765c8d7a87a6a4ae28edffb8b7085bbd9bc78a06a7b970eea026e60ac29bb52aee10661a4222e6bdcdfb3839a80586e584586b4
FeePayerPrivateKey 0xb9d5558443585bca6f225b935950e3f6e69f9da8a5809a83f51c3365dff53936
FeePayerPublicKey.X 0x327434d4cfc66ef8857d431419e9deebdc53a3e415edcc55382e2d417b8dd102
FeePayerPublicKey.Y 0x65fc97045707faf7b8f81ac65089d4cc71f69ad0bf1bc8559bc24f13fc284ced
SigRLPFeePayer 0xf857b83df83b128204d219830f4240947b65b75d204abed71587c9e519a89277766ee1d00a94a94f5374fce5edbc8e2a8697c15331677e6ebf0b8568656c6c6f1e945a0043070275d9f6054307ee7348bd660849d90f018080
SigHashFeePayer 0x09583a871c38a4860e336bfa5f16003feec75e710cfd9186c37892cee7d9775b
SignatureFeePayer f845f84325a0c1c54bdc72ce7c08821329bf50542535fac74f4bba5de5b7881118a461d52834a03a3a64878d784f9af91c2e3ab9c90f17144c47cfd9951e3588c75063c0649ecd
TxHashRLP 0x12f8dd8204d219830f4240947b65b75d204abed71587c9e519a89277766ee1d00a94a94f5374fce5edbc8e2a8697c15331677e6ebf0b8568656c6c6f1ef845f84326a0769f0afdc310289f9b24decb5bb765c8d7a87a6a4ae28edffb8b7085bbd9bc78a06a7b970eea026e60ac29bb52aee10661a4222e6bdcdfb3839a80586e584586b4945a0043070275d9f6054307ee7348bd660849d90ff845f84325a0c1c54bdc72ce7c08821329bf50542535fac74f4bba5de5b7881118a461d52834a03a3a64878d784f9af91c2e3ab9c90f17144c47cfd9951e3588c75063c0649ecd
TxHash abcb0fd8ebb8f62ac899e5211b9ba47fe948a8efd815229cc4ed9cd781464f15
SenderTxHashRLP 0x12f87b8204d219830f4240947b65b75d204abed71587c9e519a89277766ee1d00a94a94f5374fce5edbc8e2a8697c15331677e6ebf0b1ef845f84326a0769f0afdc310289f9b24decb5bb765c8d7a87a6a4ae28edffb8b7085bbd9bc78a06a7b970eea026e60ac29bb52aee10661a4222e6bdcdfb3839a80586e584586b4
SenderTxHash 2c4e8cd3c68a4aacae51c695e857cfc1a019037ca71d8cd1e8ca56ec4eaf55b1

    TX(abcb0fd8ebb8f62ac899e5211b9ba47fe948a8efd815229cc4ed9cd781464f15)
    Type:          TxTypeFeeDelegatedValueTransferMemoWithRatio
    From:          0xa94f5374Fce5edBC8E2a8697C15331677e6EbF0B
    To:            0x7b65B75d204aBed71587c9E519a89277766EE1d0
    Nonce:         1234
    GasPrice:      0x19
    GasLimit:      0xf4240
    Value:         0xa
    Signature:     [{"V":"0x26","R":"0x769f0afdc310289f9b24decb5bb765c8d7a87a6a4ae28edffb8b7085bbd9bc78","S":"0x6a7b970eea026e60ac29bb52aee10661a4222e6bdcdfb3839a80586e584586b4"}]
    FeePayer:      0x5A0043070275d9f6054307Ee7348bD660849D90f
    FeeRatio:      30
    FeePayerSig:   [{"V":"0x25","R":"0xc1c54bdc72ce7c08821329bf50542535fac74f4bba5de5b7881118a461d52834","S":"0x3a3a64878d784f9af91c2e3ab9c90f17144c47cfd9951e3588c75063c0649ecd"}]
    Data:          36383635366336633666
    Hex:           12f8dd8204d219830f4240947b65b75d204abed71587c9e519a89277766ee1d00a94a94f5374fce5edbc8e2a8697c15331677e6ebf0b8568656c6c6f1ef845f84326a0769f0afdc310289f9b24decb5bb765c8d7a87a6a4ae28edffb8b7085bbd9bc78a06a7b970eea026e60ac29bb52aee10661a4222e6bdcdfb3839a80586e584586b4945a0043070275d9f6054307ee7348bd660849d90ff845f84325a0c1c54bdc72ce7c08821329bf50542535fac74f4bba5de5b7881118a461d52834a03a3a64878d784f9af91c2e3ab9c90f17144c47cfd9951e3588c75063c0649ecd
```

### Kết quả đầu ra RPC (Example) <a href="#rpc-output-example" id="rpc-output-example"></a>

Phần dưới đây cho thấy một đối tượng giao dịch được trả về qua JSON RPC.

```javascript
{
  "blockHash": "0x7ad6ed1f9955be00db8fb5452125f0e9a3c0856abb5b4cc4aed91ffc134321da",
  "blockNumber": "0x1",
  "contractAddress": null,
  "feePayer": "0x029fdce0457db02f05c4be9f67b7115cb8ea15ca",
  "feePayerSignatures": [
    {
      "V": "0x26",
      "R": "0x1f71cc0dee26dce62a987d189650ee62a6751fcde1c7f7915abaf6c0137930da",
      "S": "0x585115c7eecb3a88e3805a90be8cb6458f245029274a781afd2b867579ff73fa"
    }
  ],
  "feeRatio": "0x1e",
  "from": "0x0fcda0f2efbe1b4e61b487701ce4f2f8abc3723d",
  "gas": "0x174876e800",
  "gasPrice": "0x5d21dba00",
  "gasUsed": "0x8e94",
  "input": "0x68656c6c6f",
  "nhật ký": [],
  "nhật kýBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
  "nonce": "0x6",
  "senderTxHash": "0xe68e9194c5448d17137f00aae392ade4d8a143c1ae4f3c5a2340a332bce009e4",
  "signatures": [
    {
      "V": "0x25",
      "R": "0x60e5da74cc0f7d73b57dc4b2a5bb7dd05d40757b47febc079e3a43769878abc3",
      "S": "0x68e16f2a7bce21e16cebbe22a3624aa5edd814dd74a70ab8aaf850cd7a4b757f"
    }
  ],
  "trạng thái": "0x1",
  "to": "0x75c3098be5e4b63fbac05838daaee378dd48098d",
  "transactionHash": "0xda18ebcf420af8a0a7acf6636711540f71b8bb65bc86e960e6a6bbb665a062f3",
  "transactionIndex": "0x6",
  "type": "TxTypeFeeDelegatedValueTransferMemoWithRatio",
  "typeInt": 18,
  "value": "0x989680"
}
```

## TxTypeFeeDelegatedSmartContractDeployWithRatio <a href="#txtypefeedelegatedsmartcontractdeploywithratio" id="txtypefeedelegatedsmartcontractdeploywithratio"></a>

TxTypeFeeDelegatedSmartContractDeployWithRatio triển khai một hợp đồng thông minh. Tỷ lệ cho trước của phí giao dịch do người trả phí thanh toán. Các thay đổi sau sẽ được tạo ra nhờ loại giao dịch này.

1. Số dư của người trả phí giảm đi theo tỷ lệ phí của khoản phí giao dịch.
2. Số dư của người gửi giảm đi một lượng bằng phần còn lại của phí giao dịch. Ví dụ: Nếu `feeRatio` là 30 thì 30% của khoản phí sẽ do người trả phí thanh toán và phần 70% còn lại của khoản phí sẽ do người gửi thanh toán.
3. Số dùng một lần của người gửi tăng thêm một đơn vị.
4. Một hợp đồng thông minh được triển khai bằng mã trong `input`. Địa chỉ đã triển khai sẽ được trả về qua `contractAddress` trong biên lai.
5. `value` KLAY sẽ được chuyển từ người gửi đến người nhận.

### Thuộc tính <a href="#attributes" id="attributes"></a>

| Thuộc tính         | type                                      | Mô tả                                                                                                                                                                                                                                                                                                                                    |
| ------------------ | ----------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| type               | uint8 (Go)                                | Loại TxTypeFeeDelegatedSmartContractDeployWithRatio. Thuộc tính này phải là 0x2a.                                                                                                                                                                                                                                                        |
| nonce              | uint64 (Go)                               | Giá trị dùng để định danh duy nhất cho một giao dịch của người gửi. Nếu hai giao dịch có cùng một giá trị số dùng một lần do người gửi tạo ra, chỉ có một giao dịch sẽ được thực thi.                                                                                                                                                    |
| giá gas            | \*big.Int (Go)                            | Đơn giá của gas tính bằng `peb` mà người gửi sẽ dùng để thanh toán phí giao dịch. Số tiền phí giao dịch được tính theo công thức `gas` \* `gasPrice`. Ví dụ: Nếu giao dịch tốn 10 đơn vị gas và gasPrice là 10^18, phí giao dịch sẽ là 10 KLAY. Hãy xem [Đơn vị của KLAY](/content/klaytn/design/klaytn-native-coin-klay#units-of-klay). |
| gas                | uint64 (Go)                               | Lượng gas tối đa mà giao dịch được phép sử dụng.                                                                                                                                                                                                                                                                                         |
| đến                | \*common.Address (Go)                     | Địa chỉ tài khoản sẽ nhận giá trị được chuyển. Hiện tại giá trị này phải bằng 0. Tính năng xác định địa chỉ sẽ được hỗ trợ trong tương lai.                                                                                                                                                                                              |
| giá trị            | \*big.Int (Go)                            | Số lượng KLAY tính bằng `peb` sẽ được chuyển.                                                                                                                                                                                                                                                                                            |
| từ                 | common.Address (Go)                       | Địa chỉ của người gửi. Để biết thêm chi tiết, hãy xem [Xác thực chữ ký của giao dịch](/content/klaytn/design/transactions#signature-validation-of-transactions).                                                                                                                                                                         |
| nhập               | \[]byte (Go)                              | Dữ liệu được gắn kèm giao dịch, dùng để thực thi giao dịch.                                                                                                                                                                                                                                                                              |
| humanReadable      | bool (Go)                                 | Đây phải là giá trị false vì địa chỉ có thể đọc chưa được hỗ trợ. Nếu giá trị là true, giao dịch sẽ bị từ chối.                                                                                                                                                                                                                          |
| feeRatio           | uint8 (Go)                                | Tỷ lệ phí của người trả phí. Khoảng hợp lệ là từ 1 đến 99. Số không (0) không được chấp nhận. Số từ 100 trở lên cũng không được chấp nhận.                                                                                                                                                                                               |
| codeFormat         | uint8 (Go)                                | Định dạng mã của mã hợp đồng thông minh. Hiện tại, giá trị được hỗ trợ chỉ có EVM(0x00).                                                                                                                                                                                                                                                 |
| txSignatures       | \[]{\*big.Int, \*big.Int, \*big.Int} (Go) | Chữ ký của người gửi. Để biết thêm chi tiết, hãy xem [Xác thực chữ ký của giao dịch](/content/klaytn/design/transactions#signature-validation-of-transactions).                                                                                                                                                                          |
| feePayer           | common.Address (Go)                       | Địa chỉ của người trả phí.                                                                                                                                                                                                                                                                                                               |
| feePayerSignatures | \[]{\*big.Int, \*big.Int, \*big.Int} (Go) | Chữ ký của người trả phí.                                                                                                                                                                                                                                                                                                                |

### Mã hóa RLP cho chữ ký của người gửi <a href="#rlp-encoding-for-signature-of-the-sender" id="rlp-encoding-for-signature-of-the-sender"></a>

Để tạo chữ ký của người gửi, quá trình tuần tự hóa RLP phải diễn ra như sau:

```javascript
SigRLP = encode([encode([type, nonce, gasPrice, gas, to, value, from, input, humanReadable, feeRatio, codeFormat]), chainid, 0, 0])
SigHash = keccak256(SigRLP)
Signature = sign(SigHash, <the sender's private key>)
```

### Mã hóa RLP cho chữ ký của người trả phí <a href="#rlp-encoding-for-signature-of-the-fee-payer" id="rlp-encoding-for-signature-of-the-fee-payer"></a>

Để tạo chữ ký của người trả phí, quá trình tuần tự hóa RLP phải diễn ra như sau:

```javascript
SigFeePayerRLP = encode([encode([type, nonce, gasPrice, gas, to, value, from, input, humanReadable, feeRatio, codeFormat]), feePayer, chainid, 0, 0])
SigFeePayerHash = keccak256(SigFeePayerRLP)
SignatureFeePayer = sign(SigFeePayerHash, <the fee payer's private key>)
```

### Mã hóa RLP cho SenderTxHash <a href="#rlp-encoding-for-sendertxhash" id="rlp-encoding-for-sendertxhash"></a>

Để tạo một SenderTxHash, quá trình tuần tự hóa RLP phải diễn ra như sau:

```javascript
txSignatures (a single signature) = [[v, r, s]]
txSignatures (two signatures) = [[v1, r1, s1], [v2, r2, s2]]
SenderTxHashRLP = type + encode([nonce, gasPrice, gas, to, value, from, input, humanReadable, feeRatio, codeFormat, txSignatures])
SenderTxHash = keccak256(SenderTxHashRLP)
```

### Mã hóa RLP cho hàm băm giao dịch <a href="#rlp-encoding-for-transaction-hash" id="rlp-encoding-for-transaction-hash"></a>

Để tạo một hàm băm giao dịch, quá trình tuần tự hóa RLP phải diễn ra như sau:

```javascript
txSignatures (a single signature) = [[v, r, s]]
txSignatures (two signatures) = [[v1, r1, s1], [v2, r2, s2]]
feePayerSignatures (a single signature) = [[v, r, s]]
feePayerSignatures (two signatures) = [[v1, r1, s1], [v2, r2, s2]]
TxHashRLP = type + encode([nonce, gasPrice, gas, to, value, from, input, humanReadable, feeRatio, codeFormat, txSignatures, feePayer, feePayerSignatures])
TxHash = keccak256(TxHashRLP)
```

### Mã hóa RLP (Ví dụ) <a href="#rlp-encoding-example" id="rlp-encoding-example"></a>

Phần dưới đây cho thấy kết quả của quá trình tuần tự hóa RLP và đối tượng giao dịch:

```javascript
ChainID 0x1
PrivateKey 0x45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8
PublicKey.X 0x3a514176466fa815ed481ffad09110a2d344f6c9b78c1d14afc351c3a51be33d
PublicKey.Y 0x8072e77939dc03ba44790779b7a1025baf3003f6732430e20cd9b76d953391b3
SigRLP 0xf90241b9023bf902382a8204d219830f4240947b65b75d204abed71587c9e519a89277766ee1d00a94a94f5374fce5edbc8e2a8697c15331677e6ebf0bb901fe608060405234801561001057600080fd5b506101de806100206000396000f3006080604052600436106100615763ffffffff7c01000000000000000000000000000000000000000000000000000000006000350416631a39d8ef81146100805780636353586b146100a757806370a08231146100ca578063fd6b7ef8146100f8575b3360009081526001602052604081208054349081019091558154019055005b34801561008c57600080fd5b5061009561010d565b60408051918252519081900360200190f35b6100c873ffffffffffffffffffffffffffffffffffffffff60043516610113565b005b3480156100d657600080fd5b5061009573ffffffffffffffffffffffffffffffffffffffff60043516610147565b34801561010457600080fd5b506100c8610159565b60005481565b73ffffffffffffffffffffffffffffffffffffffff1660009081526001602052604081208054349081019091558154019055565b60016020526000908152604090205481565b336000908152600160205260408120805490829055908111156101af57604051339082156108fc029083906000818181858888f193505050501561019c576101af565b3360009081526001602052604090208190555b505600a165627a7a72305820627ca46bb09478a015762806cc00c431230501118c7c26c30ac58c4e09e51c4f0029011e80018080
SigHash 0x000db9e2246975d7242e2fb45279ff42bc0269e544e3b1589ea78e760775cc2c
Signature f845f84326a0cfe8dc29d31916b3f661a4774cb8d44d39ae700a9fb6ca04327f84bbe4de1486a01616e09ced403420cac1363d14e705b7a323518b1ce5124b16f06871c00ac424
FeePayerPrivateKey 0xb9d5558443585bca6f225b935950e3f6e69f9da8a5809a83f51c3365dff53936
FeePayerPublicKey.X 0x327434d4cfc66ef8857d431419e9deebdc53a3e415edcc55382e2d417b8dd102
FeePayerPublicKey.Y 0x65fc97045707faf7b8f81ac65089d4cc71f69ad0bf1bc8559bc24f13fc284ced
SigRLPFeePayer 0xf90256b9023bf902382a8204d219830f4240947b65b75d204abed71587c9e519a89277766ee1d00a94a94f5374fce5edbc8e2a8697c15331677e6ebf0bb901fe608060405234801561001057600080fd5b506101de806100206000396000f3006080604052600436106100615763ffffffff7c01000000000000000000000000000000000000000000000000000000006000350416631a39d8ef81146100805780636353586b146100a757806370a08231146100ca578063fd6b7ef8146100f8575b3360009081526001602052604081208054349081019091558154019055005b34801561008c57600080fd5b5061009561010d565b60408051918252519081900360200190f35b6100c873ffffffffffffffffffffffffffffffffffffffff60043516610113565b005b3480156100d657600080fd5b5061009573ffffffffffffffffffffffffffffffffffffffff60043516610147565b34801561010457600080fd5b506100c8610159565b60005481565b73ffffffffffffffffffffffffffffffffffffffff1660009081526001602052604081208054349081019091558154019055565b60016020526000908152604090205481565b336000908152600160205260408120805490829055908111156101af57604051339082156108fc029083906000818181858888f193505050501561019c576101af565b3360009081526001602052604090208190555b505600a165627a7a72305820627ca46bb09478a015762806cc00c431230501118c7c26c30ac58c4e09e51c4f0029011e80945a0043070275d9f6054307ee7348bd660849d90f018080
SigHashFeePayer 0xedd4031ccfb27867cbd856192cec0a538ab25f6bc632f3075bf7be8368983cea
SignatureFeePayer f845f84325a0e29dae81defc027f059cd6a55ff74156b9c5bdb811460f09fc8d167c01aaaea1a04eba34d4d5ebbce60e4998f03b7a4658263bb21063ddf68ad3b088d670de47c8
TxHashRLP 0x2af902da8204d219830f4240947b65b75d204abed71587c9e519a89277766ee1d00a94a94f5374fce5edbc8e2a8697c15331677e6ebf0bb901fe608060405234801561001057600080fd5b506101de806100206000396000f3006080604052600436106100615763ffffffff7c01000000000000000000000000000000000000000000000000000000006000350416631a39d8ef81146100805780636353586b146100a757806370a08231146100ca578063fd6b7ef8146100f8575b3360009081526001602052604081208054349081019091558154019055005b34801561008c57600080fd5b5061009561010d565b60408051918252519081900360200190f35b6100c873ffffffffffffffffffffffffffffffffffffffff60043516610113565b005b3480156100d657600080fd5b5061009573ffffffffffffffffffffffffffffffffffffffff60043516610147565b34801561010457600080fd5b506100c8610159565b60005481565b73ffffffffffffffffffffffffffffffffffffffff1660009081526001602052604081208054349081019091558154019055565b60016020526000908152604090205481565b336000908152600160205260408120805490829055908111156101af57604051339082156108fc029083906000818181858888f193505050501561019c576101af565b3360009081526001602052604090208190555b505600a165627a7a72305820627ca46bb09478a015762806cc00c431230501118c7c26c30ac58c4e09e51c4f0029011e80f845f84326a0cfe8dc29d31916b3f661a4774cb8d44d39ae700a9fb6ca04327f84bbe4de1486a01616e09ced403420cac1363d14e705b7a323518b1ce5124b16f06871c00ac424945a0043070275d9f6054307ee7348bd660849d90ff845f84325a0e29dae81defc027f059cd6a55ff74156b9c5bdb811460f09fc8d167c01aaaea1a04eba34d4d5ebbce60e4998f03b7a4658263bb21063ddf68ad3b088d670de47c8
TxHash 54b6f267c2dd508ffdd9d41fd6d04847ad975cede8fcd4d5af58ca959c534946
SenderTxHashRLP 0x2af9027e8204d219830f4240947b65b75d204abed71587c9e519a89277766ee1d00a94a94f5374fce5edbc8e2a8697c15331677e6ebf0bb901fe608060405234801561001057600080fd5b506101de806100206000396000f3006080604052600436106100615763ffffffff7c01000000000000000000000000000000000000000000000000000000006000350416631a39d8ef81146100805780636353586b146100a757806370a08231146100ca578063fd6b7ef8146100f8575b3360009081526001602052604081208054349081019091558154019055005b34801561008c57600080fd5b5061009561010d565b60408051918252519081900360200190f35b6100c873ffffffffffffffffffffffffffffffffffffffff60043516610113565b005b3480156100d657600080fd5b5061009573ffffffffffffffffffffffffffffffffffffffff60043516610147565b34801561010457600080fd5b506100c8610159565b60005481565b73ffffffffffffffffffffffffffffffffffffffff1660009081526001602052604081208054349081019091558154019055565b60016020526000908152604090205481565b336000908152600160205260408120805490829055908111156101af57604051339082156108fc029083906000818181858888f193505050501561019c576101af565b3360009081526001602052604090208190555b505600a165627a7a72305820627ca46bb09478a015762806cc00c431230501118c7c26c30ac58c4e09e51c4f0029011e80f845f84326a0cfe8dc29d31916b3f661a4774cb8d44d39ae700a9fb6ca04327f84bbe4de1486a01616e09ced403420cac1363d14e705b7a323518b1ce5124b16f06871c00ac424
SenderTxHash 57dfef9c923cba182cca00fa65d45aaf619613d843d585d3c4026a3bd0797366

    TX(54b6f267c2dd508ffdd9d41fd6d04847ad975cede8fcd4d5af58ca959c534946)
    Type:          TxTypeFeeDelegatedSmartContractDeployWithRatio
    From:          0xa94f5374Fce5edBC8E2a8697C15331677e6EbF0B
    To:            0x7b65B75d204aBed71587c9E519a89277766EE1d0
    Nonce:         1234
    GasPrice:      0x19
    GasLimit:      0xf4240
    Value:         0xa
    Data:          363038303630343035323334383031353631303031303537363030303830666435623530363130316465383036313030323036303030333936303030663330303630383036303430353236303034333631303631303036313537363366666666666666663763303130303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303630303033353034313636333161333964386566383131343631303038303537383036333633353335383662313436313030613735373830363337306130383233313134363130306361353738303633666436623765663831343631303066383537356233333630303039303831353236303031363032303532363034303831323038303534333439303831303139303931353538313534303139303535303035623334383031353631303038633537363030303830666435623530363130303935363130313064353635623630343038303531393138323532353139303831393030333630323030313930663335623631303063383733666666666666666666666666666666666666666666666666666666666666666666666666666666663630303433353136363130313133353635623030356233343830313536313030643635373630303038306664356235303631303039353733666666666666666666666666666666666666666666666666666666666666666666666666666666663630303433353136363130313437353635623334383031353631303130343537363030303830666435623530363130306338363130313539353635623630303035343831353635623733666666666666666666666666666666666666666666666666666666666666666666666666666666663136363030303930383135323630303136303230353236303430383132303830353433343930383130313930393135353831353430313930353535363562363030313630323035323630303039303831353236303430393032303534383135363562333336303030393038313532363030313630323035323630343038313230383035343930383239303535393038313131313536313031616635373630343035313333393038323135363130386663303239303833393036303030383138313831383538383838663139333530353035303530313536313031396335373631303161663536356233333630303039303831353236303031363032303532363034303930323038313930353535623530353630306131363536323761376137323330353832303632376361343662623039343738613031353736323830366363303063343331323330353031313138633763323663333061633538633465303965353163346630303239
    HumanReadable: true
    Signature:     [{"V":"0x26","R":"0xcfe8dc29d31916b3f661a4774cb8d44d39ae700a9fb6ca04327f84bbe4de1486","S":"0x1616e09ced403420cac1363d14e705b7a323518b1ce5124b16f06871c00ac424"}]
    FeePayer:      0x5A0043070275d9f6054307Ee7348bD660849D90f
    FeeRatio:      30
    CodeFormat:    CodeFormatEVM
    FeePayerSig:   [{"V":"0x25","R":"0xe29dae81defc027f059cd6a55ff74156b9c5bdb811460f09fc8d167c01aaaea1","S":"0x4eba34d4d5ebbce60e4998f03b7a4658263bb21063ddf68ad3b088d670de47c8"}]
    Hex:           2af902da8204d219830f4240947b65b75d204abed71587c9e519a89277766ee1d00a94a94f5374fce5edbc8e2a8697c15331677e6ebf0bb901fe608060405234801561001057600080fd5b506101de806100206000396000f3006080604052600436106100615763ffffffff7c01000000000000000000000000000000000000000000000000000000006000350416631a39d8ef81146100805780636353586b146100a757806370a08231146100ca578063fd6b7ef8146100f8575b3360009081526001602052604081208054349081019091558154019055005b34801561008c57600080fd5b5061009561010d565b60408051918252519081900360200190f35b6100c873ffffffffffffffffffffffffffffffffffffffff60043516610113565b005b3480156100d657600080fd5b5061009573ffffffffffffffffffffffffffffffffffffffff60043516610147565b34801561010457600080fd5b506100c8610159565b60005481565b73ffffffffffffffffffffffffffffffffffffffff1660009081526001602052604081208054349081019091558154019055565b60016020526000908152604090205481565b336000908152600160205260408120805490829055908111156101af57604051339082156108fc029083906000818181858888f193505050501561019c576101af565b3360009081526001602052604090208190555b505600a165627a7a72305820627ca46bb09478a015762806cc00c431230501118c7c26c30ac58c4e09e51c4f0029011e80f845f84326a0cfe8dc29d31916b3f661a4774cb8d44d39ae700a9fb6ca04327f84bbe4de1486a01616e09ced403420cac1363d14e705b7a323518b1ce5124b16f06871c00ac424945a0043070275d9f6054307ee7348bd660849d90ff845f84325a0e29dae81defc027f059cd6a55ff74156b9c5bdb811460f09fc8d167c01aaaea1a04eba34d4d5ebbce60e4998f03b7a4658263bb21063ddf68ad3b088d670de47c8
```

### Kết quả đầu ra RPC (Example) <a href="#rpc-output-example" id="rpc-output-example"></a>

Phần dưới đây cho thấy một đối tượng giao dịch được trả về qua JSON RPC.

```javascript
{
  "blockHash": "0x82983fe294d286e76486760e6904369285554e1744af16786c2393a956fb4ec4",
  "blockNumber": "0x2",
  "codeFormat": "0x0",
  "contractAddress": "0x636f6e7472616374332e6b6c6179746e00000000",
  "feePayer": "0x029fdce0457db02f05c4be9f67b7115cb8ea15ca",
  "feePayerSignatures": [
    {
      "V": "0x25",
      "R": "0x9dbd19852ce8d1bc36389c73aa45733ccd2af0186d78952ca2b7bf3828227c02",
      "S": "0x184f60af32203d5abd0e1ac8820887cc96189d4efc1ccddb5fb966e29a07c9cf"
    }
  ],
  "feeRatio": "0x21",
  "from": "0x0fcda0f2efbe1b4e61b487701ce4f2f8abc3723d",
  "gas": "0x174876e800",
  "gasPrice": "0x0",
  "gasUsed": "0xee6e6ed5",
  "humanReadable": true,
  "input": "0x608060405234801561001057600080fd5b506101de806100206000396000f3006080604052600436106100615763ffffffff7c01000000000000000000000000000000000000000000000000000000006000350416631a39d8ef81146100805780636353586b146100a757806370a08231146100ca578063fd6b7ef8146100f8575b3360009081526001602052604081208054349081019091558154019055005b34801561008c57600080fd5b5061009561010d565b60408051918252519081900360200190f35b6100c873ffffffffffffffffffffffffffffffffffffffff60043516610113565b005b3480156100d657600080fd5b5061009573ffffffffffffffffffffffffffffffffffffffff60043516610147565b34801561010457600080fd5b506100c8610159565b60005481565b73ffffffffffffffffffffffffffffffffffffffff1660009081526001602052604081208054349081019091558154019055565b60016020526000908152604090205481565b336000908152600160205260408120805490829055908111156101af57604051339082156108fc029083906000818181858888f193505050501561019c576101af565b3360009081526001602052604090208190555b505600a165627a7a72305820627ca46bb09478a015762806cc00c431230501118c7c26c30ac58c4e09e51c4f0029",
  "nhật ký": [],
  "nhật kýBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
  "nonce": "0xc",
  "senderTxHash": "0xe24e58467268601dc5131fb9719ebbb4bed16244af05c37d916a92c98a6a62a5",
  "signatures": [
    {
      "V": "0x26",
      "R": "0xb9497df1dd5c37786570f26745112fb828fb7b6de851bc11562eab77a76462b1",
      "S": "0x6231f2945f01004e68388ad1103cb00fd4f3f8b782667030d99779ecd47d7462"
    }
  ],
  "trạng thái": "0x1",
  "to": "0x636f6e7472616374332e6b6c6179746e00000000",
  "transactionHash": "0x32944e85f2255b7ebc1101b136938a758295d57dca1203b997e7ee7873dd9eec",
  "transactionIndex": "0x5",
  "type": "TxTypeFeeDelegatedSmartContractDeployWithRatio",
  "typeInt": 42,
  "value": "0x0"
}
```

## TxTypeFeeDelegatedSmartContractExecutionWithRatio <a href="#txtypefeedelegatedsmartcontractexecutionwithratio" id="txtypefeedelegatedsmartcontractexecutionwithratio"></a>

TxTypeFeeDelegatedSmartContractExecution thực thi hợp đồng thông minh với dữ liệu đã cho trong `input`. TxTypeFeeDelegatedSmartContractExecutionWithRatio chỉ được chấp nhận nếu `to` là một tài khoản hợp đồng thông minh. Để chuyển KLAY đến một tài khoản thuộc sở hữu bên ngoài, hãy dùng [TxTypeFeeDelegatedValueTransferWithRatio](#txtypefeedelegatedvaluetransferwithratio). Các thay đổi sau sẽ được tạo ra nhờ loại giao dịch này.

1. Nếu `to` là một tài khoản hợp đồng thông minh, mã sẽ được thực thi dựa trên `input`. Nếu không, giao dịch sẽ bị từ chối.
2. Số dư của người trả phí giảm đi theo tỷ lệ phí của khoản phí giao dịch.
3. Số dư của người gửi giảm đi một lượng bằng phần còn lại của phí giao dịch. Ví dụ: Nếu `feeRatio` là 30 thì 30% của khoản phí sẽ do người trả phí thanh toán và phần 70% còn lại của khoản phí sẽ do người gửi thanh toán.
4. Số dùng một lần của người gửi tăng thêm một đơn vị.
5. Nếu `value` được cung cấp, `value` KLAY được chuyển từ người gửi đến `to` của hợp đồng thông minh. Hợp đồng phải có hàm dự phòng khoản phải trả để nhận KLAY.

### Thuộc tính <a href="#attributes" id="attributes"></a>

| Thuộc tính         | Loại                                     | Mô tả                                                                                                                                                                                                                                                                                                                                    |
| ------------------ | ----------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| type               | uint8 (Go)                                | Loại TxTypeFeeDelegatedSmartContractExecutionWithRatio. Thuộc tính này phải là 0x32.                                                                                                                                                                                                                                                     |
| nonce              | uint64 (Go)                               | Giá trị dùng để định danh duy nhất cho một giao dịch của người gửi. Nếu hai giao dịch có cùng một giá trị số dùng một lần do người gửi tạo ra, chỉ có một giao dịch sẽ được thực thi.                                                                                                                                                    |
| giá gas            | \*big.Int (Go)                            | Đơn giá của gas tính bằng `peb` mà người gửi sẽ dùng để thanh toán phí giao dịch. Số tiền phí giao dịch được tính theo công thức `gas` \* `gasPrice`. Ví dụ: Nếu giao dịch tốn 10 đơn vị gas và gasPrice là 10^18, phí giao dịch sẽ là 10 KLAY. Hãy xem [Đơn vị của KLAY](/content/klaytn/design/klaytn-native-coin-klay#units-of-klay). |
| gas                | uint64 (Go)                               | Lượng gas tối đa mà giao dịch được phép sử dụng.                                                                                                                                                                                                                                                                                         |
| đến                | common.Address (Go)                       | Địa chỉ thực thi tài khoản hợp đồng thông minh.                                                                                                                                                                                                                                                                                          |
| giá trị            | \*big.Int (Go)                            | Số lượng KLAY tính bằng `peb` sẽ được chuyển.                                                                                                                                                                                                                                                                                            |
| từ                 | common.Address (Go)                       | Địa chỉ của người gửi. Để biết thêm chi tiết, hãy xem [Xác thực chữ ký của giao dịch](/content/klaytn/design/transactions#signature-validation-of-transactions).                                                                                                                                                                         |
| nhập               | \[]byte (Go)                              | Dữ liệu được gắn kèm giao dịch, dùng để thực thi giao dịch.                                                                                                                                                                                                                                                                              |
| feeRatio           | uint8 (Go)                                | Tỷ lệ phí của người trả phí. Khoảng hợp lệ là từ 1 đến 99. Số không (0) không được chấp nhận. Số từ 100 trở lên cũng không được chấp nhận.                                                                                                                                                                                               |
| txSignatures       | \[]{\*big.Int, \*big.Int, \*big.Int} (Go) | Chữ ký của người gửi. Để biết thêm chi tiết, hãy xem [Xác thực chữ ký của giao dịch](/content/klaytn/design/transactions#signature-validation-of-transactions).                                                                                                                                                                          |
| feePayer           | common.Address (Go)                       | Địa chỉ của người trả phí.                                                                                                                                                                                                                                                                                                               |
| feePayerSignatures | \[]{\*big.Int, \*big.Int, \*big.Int} (Go) | Chữ ký của người trả phí.                                                                                                                                                                                                                                                                                                                |

### Mã hóa RLP cho chữ ký của người gửi <a href="#rlp-encoding-for-signature-of-the-sender" id="rlp-encoding-for-signature-of-the-sender"></a>

Để tạo chữ ký của người gửi, quá trình tuần tự hóa RLP phải diễn ra như sau:

```javascript
SigRLP = encode([encode([type, nonce, gasPrice, gas, to, value, from, input, feeRatio]), chainid, 0, 0])
SigHash = keccak256(SigRLP)
Signature = sign(SigHash, <the sender's private key>)
```

### Mã hóa RLP cho chữ ký của người trả phí <a href="#rlp-encoding-for-signature-of-the-fee-payer" id="rlp-encoding-for-signature-of-the-fee-payer"></a>

Để tạo chữ ký của người trả phí, quá trình tuần tự hóa RLP phải diễn ra như sau:

```javascript
SigFeePayerRLP = encode([encode([type, nonce, gasPrice, gas, to, value, from, input, feeRatio]), feePayer, chainid, 0, 0])
SigFeePayerHash = keccak256(SigFeePayerRLP)
SignatureFeePayer = sign(SigFeePayerHash, <the fee payer's private key>)
```

### Mã hóa RLP cho SenderTxHash <a href="#rlp-encoding-for-sendertxhash" id="rlp-encoding-for-sendertxhash"></a>

Để tạo một SenderTxHash, quá trình tuần tự hóa RLP phải diễn ra như sau:

```javascript
txSignatures (a single signature) = [[v, r, s]]
txSignatures (two signatures) = [[v1, r1, s1], [v2, r2, s2]]
SenderTxHashRLP = type + encode([nonce, gasPrice, gas, to, value, from, input, feeRatio, txSignatures])
SenderTxHash = keccak256(SenderTxHashRLP)
```

### Mã hóa RLP cho hàm băm giao dịch <a href="#rlp-encoding-for-transaction-hash" id="rlp-encoding-for-transaction-hash"></a>

Để tạo một hàm băm giao dịch, quá trình tuần tự hóa RLP phải diễn ra như sau:

```javascript
TxHashRLP = type + encode([nonce, gasPrice, gas, to, value, from, input, feeRatio, txSignatures, feePayer, feePayerSignatures])
TxHash = keccak256(TxHashRLP)
```

### Mã hóa RLP (Ví dụ) <a href="#rlp-encoding-example" id="rlp-encoding-example"></a>

Phần dưới đây cho thấy kết quả của quá trình tuần tự hóa RLP và đối tượng giao dịch:

```javascript
ChainID 0x1
PrivateKey 0x45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8
PublicKey.X 0x3a514176466fa815ed481ffad09110a2d344f6c9b78c1d14afc351c3a51be33d
PublicKey.Y 0x8072e77939dc03ba44790779b7a1025baf3003f6732430e20cd9b76d953391b3
SigRLP 0xf861b85cf85a328204d219830f4240947b65b75d204abed71587c9e519a89277766ee1d00a94a94f5374fce5edbc8e2a8697c15331677e6ebf0ba46353586b000000000000000000000000bc5951f055a85f41a3b62fd6f68ab7de76d299b21e018080
SigHash 0x1eeea77acecdd102a070ead80a00f388e039c11d813e6d4a63ec90bd0186b210
Signature f845f84326a074ccfee18dc28932396b85617c53784ee366303bce39a2401d8eb602cf73766fa04c937a5ab9401d2cacb3f39ba8c29dbcd44588cc5c7d0b6b4113cfa7b7d9427b
FeePayerPrivateKey 0xb9d5558443585bca6f225b935950e3f6e69f9da8a5809a83f51c3365dff53936
FeePayerPublicKey.X 0x327434d4cfc66ef8857d431419e9deebdc53a3e415edcc55382e2d417b8dd102
FeePayerPublicKey.Y 0x65fc97045707faf7b8f81ac65089d4cc71f69ad0bf1bc8559bc24f13fc284ced
SigRLPFeePayer 0xf876b85cf85a328204d219830f4240947b65b75d204abed71587c9e519a89277766ee1d00a94a94f5374fce5edbc8e2a8697c15331677e6ebf0ba46353586b000000000000000000000000bc5951f055a85f41a3b62fd6f68ab7de76d299b21e945a0043070275d9f6054307ee7348bd660849d90f018080
SigHashFeePayer 0x8a13f42530219cddb490108e38c48e7b58bc02a82f4d797d8f4d85eb16f6d6a5
SignatureFeePayer f845f84325a04a4997524694d535976d7343c1e3a260f99ba53fcb5477e2b96216ec96ebb565a00f8cb31a35399d2b0fbbfa39f259c819a15370706c0449952c7cfc682d200d7c
TxHashRLP 0x32f8fc8204d219830f4240947b65b75d204abed71587c9e519a89277766ee1d00a94a94f5374fce5edbc8e2a8697c15331677e6ebf0ba46353586b000000000000000000000000bc5951f055a85f41a3b62fd6f68ab7de76d299b21ef845f84326a074ccfee18dc28932396b85617c53784ee366303bce39a2401d8eb602cf73766fa04c937a5ab9401d2cacb3f39ba8c29dbcd44588cc5c7d0b6b4113cfa7b7d9427b945a0043070275d9f6054307ee7348bd660849d90ff845f84325a04a4997524694d535976d7343c1e3a260f99ba53fcb5477e2b96216ec96ebb565a00f8cb31a35399d2b0fbbfa39f259c819a15370706c0449952c7cfc682d200d7c
TxHash b204e530f2a7f010d65b6f0f7639d1e9fc8add73e3a0ff1551b11585c36d3bdb
SenderTxHashRLP 0x32f8a08204d219830f4240947b65b75d204abed71587c9e519a89277766ee1d00a94a94f5374fce5edbc8e2a8697c15331677e6ebf0ba46353586b000000000000000000000000bc5951f055a85f41a3b62fd6f68ab7de76d299b21ef845f84326a074ccfee18dc28932396b85617c53784ee366303bce39a2401d8eb602cf73766fa04c937a5ab9401d2cacb3f39ba8c29dbcd44588cc5c7d0b6b4113cfa7b7d9427b
SenderTxHash d5e22319cbf020d422d8ba3a07da9d99b9300826637af85b4e061805dcb2c1b0

    TX(b204e530f2a7f010d65b6f0f7639d1e9fc8add73e3a0ff1551b11585c36d3bdb)
    Type:          TxTypeFeeDelegatedSmartContractExecutionWithRatio
    From:          0xa94f5374Fce5edBC8E2a8697C15331677e6EbF0B
    To:            0x7b65B75d204aBed71587c9E519a89277766EE1d0
    Nonce:         1234
    GasPrice:      0x19
    GasLimit:      0xf4240
    Value:         0xa
    Data:          363335333538366230303030303030303030303030303030303030303030303062633539353166303535613835663431613362363266643666363861623764653736643239396232
    Signature:     [{"V":"0x26","R":"0x74ccfee18dc28932396b85617c53784ee366303bce39a2401d8eb602cf73766f","S":"0x4c937a5ab9401d2cacb3f39ba8c29dbcd44588cc5c7d0b6b4113cfa7b7d9427b"}]
    FeePayer:      0x5A0043070275d9f6054307Ee7348bD660849D90f
    FeeRatio:      30
    FeePayerSig:   [{"V":"0x25","R":"0x4a4997524694d535976d7343c1e3a260f99ba53fcb5477e2b96216ec96ebb565","S":"0xf8cb31a35399d2b0fbbfa39f259c819a15370706c0449952c7cfc682d200d7c"}]
    Hex:           32f8fc8204d219830f4240947b65b75d204abed71587c9e519a89277766ee1d00a94a94f5374fce5edbc8e2a8697c15331677e6ebf0ba46353586b000000000000000000000000bc5951f055a85f41a3b62fd6f68ab7de76d299b21ef845f84326a074ccfee18dc28932396b85617c53784ee366303bce39a2401d8eb602cf73766fa04c937a5ab9401d2cacb3f39ba8c29dbcd44588cc5c7d0b6b4113cfa7b7d9427b945a0043070275d9f6054307ee7348bd660849d90ff845f84325a04a4997524694d535976d7343c1e3a260f99ba53fcb5477e2b96216ec96ebb565a00f8cb31a35399d2b0fbbfa39f259c819a15370706c0449952c7cfc682d200d7c
```

### Kết quả đầu ra RPC (Example) <a href="#rpc-output-example" id="rpc-output-example"></a>

Phần dưới đây cho thấy một đối tượng giao dịch được trả về qua JSON RPC.

```javascript
{
  "blockHash": "0x82983fe294d286e76486760e6904369285554e1744af16786c2393a956fb4ec4",
  "blockNumber": "0x2",
  "contractAddress": null,
  "feePayer": "0x029fdce0457db02f05c4be9f67b7115cb8ea15ca",
  "feePayerSignatures": [
    {
      "V": "0x26",
      "R": "0xfd7cbb13af34814ae5072b7078e9d98ca1806859f452c7369c88fed70150ddee",
      "S": "0x6edee3341b62a2ef1488636a9395bc236ebcdfebc76ee3c933d48a65ea89440e"
    }
  ],
  "feeRatio": "0x42",
  "from": "0x0fcda0f2efbe1b4e61b487701ce4f2f8abc3723d",
  "gas": "0x174876e800",
  "gasPrice": "0x0",
  "gasUsed": "0xc444",
  "input": "0x6353586b0000000000000000000000000fcda0f2efbe1b4e61b487701ce4f2f8abc3723d",
  "nhật ký": [],
  "nhật kýBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
  "nonce": "0xf",
  "senderTxHash": "0x5545f40855ac02770f8738629d2e81bd3d04df3d90bb2b6e676a10e747c0d946",
  "signatures": [
    {
      "V": "0x26",
      "R": "0xaf1fdf0874424ed6d86b1408d24e2dff36046669cf9d99282bec4a50713adfa6",
      "S": "0x20f25bf30b0d906cee734396914a5497076a7f50ce83954b09c9f46415af8f1"
    }
  ],
  "trạng thái": "0x1",
  "to": "0x636f6e74726163742e6b6c6179746e0000000000",
  "transactionHash": "0xc4af8d6b3353ad3ad240a747d185a094c6e751373c3c08c669eb37c50f01b7b1",
  "transactionIndex": "0x8",
  "type": "TxTypeFeeDelegatedSmartContractExecutionWithRatio",
  "typeInt": 50,
  "value": "0xa"
}
```

## TxTypeFeeDelegatedAccountUpdateWithRatio <a href="#txtypefeedelegatedaccountupdatewithratio" id="txtypefeedelegatedaccountupdatewithratio"></a>

TxTypeFeeDelegatedAccountUpdateWithRatio cập nhật khóa của tài khoản đã cho. Tỷ lệ cho trước của phí giao dịch do người trả phí thanh toán. Các thay đổi sau sẽ diễn ra nhờ loại giao dịch này.

1. Số dư của người trả phí giảm đi theo tỷ lệ phí của khoản phí giao dịch.
2. Số dư của người gửi giảm đi một lượng bằng phần còn lại của phí giao dịch. Ví dụ: Nếu `feeRatio` là 30 thì 30% của khoản phí sẽ do người trả phí thanh toán và phần 70% còn lại của khoản phí sẽ do người gửi thanh toán.
3. Số dùng một lần của người gửi tăng thêm một đơn vị.
4. Khóa tài khoản được cập nhật bằng `key`.
5. Các giao dịch được gửi từ tài khoản sẽ được xác thực bằng `key` này kể từ sau khi giao dịch này đã được thực thi.

### Thuộc tính <a href="#attributes" id="attributes"></a>

| Thuộc tính         | Loại                                     | Mô tả                                                                                                                                                                                                                                                                                                                                                |
| ------------------ | ----------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| type               | uint8 (Go)                                | Loại TxTypeFeeDelegatedAccountUpdateWithRatio. Thuộc tính này phải là 0x22.                                                                                                                                                                                                                                                                          |
| nonce              | uint64 (Go)                               | Giá trị dùng để định danh duy nhất cho một giao dịch của người gửi. Nếu hai giao dịch có cùng một giá trị số dùng một lần do người gửi tạo ra, chỉ có một giao dịch sẽ được thực thi.                                                                                                                                                                |
| giá gas            | \*big.Int (Go)                            | Hệ số nhân để tính toán số lượng token mà người gửi sẽ thanh toán. Lượng token mà người gửi sẽ thanh toán được tính theo công thức `gas` \* `gasPrice`. Ví dụ: Người gửi sẽ thanh toán khoản phí giao dịch là 10 KLAY nếu gas bằng 10 và gasPrice là 10^18. Hãy xem [Đơn vị của KLAY](/content/klaytn/design/klaytn-native-coin-klay#units-of-klay). |
| gas                | uint64 (Go)                               | Giá trị phí giao dịch tối đa mà giao dịch được phép sử dụng.                                                                                                                                                                                                                                                                                         |
| từ                 | common.Address (Go)                       | Địa chỉ của người gửi. Để biết thêm chi tiết, hãy xem [Xác thực chữ ký của giao dịch](/content/klaytn/design/transactions#signature-validation-of-transactions).                                                                                                                                                                                     |
| khóa               | AccountKey (Go)                           | \[AccountKey]\[] cần cập nhật cho tài khoản.                                                                                                                                                                                                                                                                                                         |
| feeRatio           | uint8 (Go)                                | Tỷ lệ phí của người trả phí. Khoảng hợp lệ là từ 1 đến 99. Số không (0) không được chấp nhận. Số từ 100 trở lên cũng không được chấp nhận.                                                                                                                                                                                                           |
| txSignatures       | \[]{\*big.Int, \*big.Int, \*big.Int} (Go) | Chữ ký của người gửi. Để biết thêm chi tiết, hãy xem [Xác thực chữ ký của giao dịch](/content/klaytn/design/transactions#signature-validation-of-transactions).                                                                                                                                                                                      |
| feePayer           | common.Address (Go)                       | Địa chỉ của người trả phí.                                                                                                                                                                                                                                                                                                                           |
| feePayerSignatures | \[]{\*big.Int, \*big.Int, \*big.Int} (Go) | Chữ ký của người trả phí.                                                                                                                                                                                                                                                                                                                            |

### Mã hóa RLP cho chữ ký của người gửi <a href="#rlp-encoding-for-signature-of-the-sender" id="rlp-encoding-for-signature-of-the-sender"></a>

Để tạo chữ ký của người gửi, quá trình tuần tự hóa RLP phải diễn ra như sau:

```javascript
SigRLP = encode([encode([type, nonce, gasPrice, gas, from, rlpEncodedKey, feeRatio]), chainid, 0, 0])
SigHash = keccak256(SigRLP)
Signature = sign(SigHash, <the sender's private key>)
```

### Mã hóa RLP cho chữ ký của người trả phí <a href="#rlp-encoding-for-signature-of-the-fee-payer" id="rlp-encoding-for-signature-of-the-fee-payer"></a>

Để tạo chữ ký của người trả phí, quá trình tuần tự hóa RLP phải diễn ra như sau:

```javascript
SigFeePayerRLP = encode([encode([type, nonce, gasPrice, gas, from, rlpEncodedKey, feeRatio]), feePayer, chainid, 0, 0])
SigFeePayerHash = keccak256(SigFeePayerRLP)
SignatureFeePayer = sign(SigFeePayerHash, <the fee payer's private key>)
```

### Mã hóa RLP cho SenderTxHash <a href="#rlp-encoding-for-sendertxhash" id="rlp-encoding-for-sendertxhash"></a>

Để tạo một SenderTxHash, quá trình tuần tự hóa RLP phải diễn ra như sau:

```javascript
txSignatures (a single signature) = [[v, r, s]]
txSignatures (two signatures) = [[v1, r1, s1], [v2, r2, s2]]
SenderTxHashRLP = type + encode([nonce, gasPrice, gas, from, rlpEncodedKey, feeRatio, txSignatures])
SenderTxHash = keccak256(SenderTxHashRLP)
```

### Mã hóa RLP cho hàm băm giao dịch <a href="#rlp-encoding-for-transaction-hash" id="rlp-encoding-for-transaction-hash"></a>

Để tạo một hàm băm giao dịch, quá trình tuần tự hóa RLP phải diễn ra như sau:

```javascript
txSignatures (a single signature) = [[v, r, s]]
txSignatures (two signatures) = [[v1, r1, s1], [v2, r2, s2]]
feePayerSignatures (a single signature) = [[v, r, s]]
feePayerSignatures (two signatures) = [[v1, r1, s1], [v2, r2, s2]]
TxHashRLP = type + encode([nonce, gasPrice, gas, from, rlpEncodedKey, feeRatio, txSignatures, feePayer, feePayerSignatures])
TxHash = keccak256(TxHashRLP)
```

### Mã hóa RLP (Ví dụ) <a href="#rlp-encoding-example" id="rlp-encoding-example"></a>

Phần dưới đây cho thấy kết quả của quá trình tuần tự hóa RLP và đối tượng giao dịch:

```javascript
ChainID 0x1
PrivateKey 0x45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8
PublicKey.X 0x3a514176466fa815ed481ffad09110a2d344f6c9b78c1d14afc351c3a51be33d
PublicKey.Y 0x8072e77939dc03ba44790779b7a1025baf3003f6732430e20cd9b76d953391b3
SigRLP 0xf84ab845f843228204d219830f424094a94f5374fce5edbc8e2a8697c15331677e6ebf0ba302a1033a514176466fa815ed481ffad09110a2d344f6c9b78c1d14afc351c3a51be33d1e018080
SigHash 0x706ba7cd01e44008077a2abeafc3aacd64cbf210f49c64983f295a2e4cc03216
Signature f845f84326a00e5929f96dec2b41343a9e6f0150eef08741fe7dcece88cc5936c49ed19051dca05a07b07017190e0baba32bdf6352f5a358a2798ed3c56e704a63819b87cf8e3f
FeePayerPrivateKey 0xb9d5558443585bca6f225b935950e3f6e69f9da8a5809a83f51c3365dff53936
FeePayerPublicKey.X 0x327434d4cfc66ef8857d431419e9deebdc53a3e415edcc55382e2d417b8dd102
FeePayerPublicKey.Y 0x65fc97045707faf7b8f81ac65089d4cc71f69ad0bf1bc8559bc24f13fc284ced
SigRLPFeePayer 0xf85fb845f843228204d219830f424094a94f5374fce5edbc8e2a8697c15331677e6ebf0ba302a1033a514176466fa815ed481ffad09110a2d344f6c9b78c1d14afc351c3a51be33d1e945a0043070275d9f6054307ee7348bd660849d90f018080
SigHashFeePayer 0xd2a51cefec667747890e6bd11fd068e8796b5446f77e152367eaa3cf98c96b30
SignatureFeePayer f845f84326a0cf8d102de7c6b0a41d3f02aefb7e419522341734c98af233408298d0c424c04ba00286f89cab4668f728d7c269997116a49b80cec8776fc64e60588a9268571e35
TxHashRLP 0x22f8e58204d219830f424094a94f5374fce5edbc8e2a8697c15331677e6ebf0ba302a1033a514176466fa815ed481ffad09110a2d344f6c9b78c1d14afc351c3a51be33d1ef845f84326a00e5929f96dec2b41343a9e6f0150eef08741fe7dcece88cc5936c49ed19051dca05a07b07017190e0baba32bdf6352f5a358a2798ed3c56e704a63819b87cf8e3f945a0043070275d9f6054307ee7348bd660849d90ff845f84326a0cf8d102de7c6b0a41d3f02aefb7e419522341734c98af233408298d0c424c04ba00286f89cab4668f728d7c269997116a49b80cec8776fc64e60588a9268571e35
TxHash 276f02c25ca4ced081dcfbb836755ced574993b047e648a583ed8d4144b3813f
SenderTxHashRLP 0x22f8898204d219830f424094a94f5374fce5edbc8e2a8697c15331677e6ebf0ba302a1033a514176466fa815ed481ffad09110a2d344f6c9b78c1d14afc351c3a51be33d1ef845f84326a00e5929f96dec2b41343a9e6f0150eef08741fe7dcece88cc5936c49ed19051dca05a07b07017190e0baba32bdf6352f5a358a2798ed3c56e704a63819b87cf8e3f
SenderTxHash e1d87538509549f4a1eb418f986bc53dc77b7eec3b2150f75cd787951d3e4b7f

    TX(276f02c25ca4ced081dcfbb836755ced574993b047e648a583ed8d4144b3813f)
    Type:          TxTypeFeeDelegatedAccountUpdateWithRatio
    From:          0xa94f5374Fce5edBC8E2a8697C15331677e6EbF0B
    Nonce:         1234
    GasPrice:      0x19
    GasLimit:      0xf4240
    Key:           AccountKeyPublic: S256Pubkey:{"x":"0x3a514176466fa815ed481ffad09110a2d344f6c9b78c1d14afc351c3a51be33d","y":"0x8072e77939dc03ba44790779b7a1025baf3003f6732430e20cd9b76d953391b3"}
    Signature:     [{"V":"0x26","R":"0xe5929f96dec2b41343a9e6f0150eef08741fe7dcece88cc5936c49ed19051dc","S":"0x5a07b07017190e0baba32bdf6352f5a358a2798ed3c56e704a63819b87cf8e3f"}]
    FeePayer:      0x5A0043070275d9f6054307Ee7348bD660849D90f
    FeeRatio:      30
    FeePayerSig:   [{"V":"0x26","R":"0xcf8d102de7c6b0a41d3f02aefb7e419522341734c98af233408298d0c424c04b","S":"0x286f89cab4668f728d7c269997116a49b80cec8776fc64e60588a9268571e35"}]
    Hex:           22f8e58204d219830f424094a94f5374fce5edbc8e2a8697c15331677e6ebf0ba302a1033a514176466fa815ed481ffad09110a2d344f6c9b78c1d14afc351c3a51be33d1ef845f84326a00e5929f96dec2b41343a9e6f0150eef08741fe7dcece88cc5936c49ed19051dca05a07b07017190e0baba32bdf6352f5a358a2798ed3c56e704a63819b87cf8e3f945a0043070275d9f6054307ee7348bd660849d90ff845f84326a0cf8d102de7c6b0a41d3f02aefb7e419522341734c98af233408298d0c424c04ba00286f89cab4668f728d7c269997116a49b80cec8776fc64e60588a9268571e35
```

### Kết quả đầu ra RPC (Example) <a href="#rpc-output-example" id="rpc-output-example"></a>

Phần dưới đây cho thấy một đối tượng giao dịch được trả về qua JSON RPC.

```javascript
{
  "blockHash": "0x82983fe294d286e76486760e6904369285554e1744af16786c2393a956fb4ec4",
  "blockNumber": "0x2",
  "contractAddress": null,
  "feePayer": "0x0fcda0f2efbe1b4e61b487701ce4f2f8abc3723d",
  "feePayerSignatures": [
    {
      "V": "0x25",
      "R": "0xfa3690925bae82ba662abe6d3af8993b7a7994d9f922cb1ae83c59c4a26a3b70",
      "S": "0x2bd481ddf40cb813dde5f67db0e3a6ad9ea46758ef97580a709b301c21530246"
    }
  ],
  "feeRatio": "0xb",
  "from": "0x636f6c696e332e6b6c6179746e00000000000000",
  "gas": "0x174876e800",
  "gasPrice": "0x5d21dba00",
  "gasUsed": "0xdac0",
  "key": "0x02a102c8785266510368d9372badd4c7f4a94b692e82ba74e0b5e26b34558b0f081447",
  "nhật ký": [],
  "nhật kýBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
  "nonce": "0x0",
  "senderTxHash": "0x74be8f01f10a497dbe9ed10659ac8c4579b37f8b5022b9f7eec6362262d44845",
  "signatures": [
    {
      "V": "0x25",
      "R": "0xd17d2ae2290b35c560289797c955fa5dc1cc25606cfd198584665917da6795ff",
      "S": "0x7bc0450ff7319ccdbf50d38095501b895717cac775c6897d2381e7182aa25742"
    }
  ],
  "trạng thái": "0x1",
  "transactionHash": "0x90ccbf85ffd1f7e74620840fd9d270e030c6719e3c7b70bb8796c1cedf02fe88",
  "transactionIndex": "0x1",
  "type": "TxTypeFeeDelegatedAccountUpdateWithRatio",
  "typeInt": 34
}
```

## TxTypeFeeDelegatedCancelWithRatio <a href="#txtypefeedelegatedcancelwithratio" id="txtypefeedelegatedcancelwithratio"></a>

TxTypeFeeDelegatedCancelWithRatio hủy bỏ việc thực thi giao dịch có cùng số dùng một lần trong bể giao dịch. Để biết thêm chi tiết, hãy xem [TxTypeCancel](/content/klaytn/design/transactions/basic#txtypecancel).

Các thay đổi sau sẽ được áp dụng nhờ loại giao dịch này. 1. Số dư của người trả phí giảm đi theo tỷ lệ phí nhất định của khoản phí giao dịch. 2. Số dư của người gửi giảm đi một lượng bằng phần còn lại của phí giao dịch. 3. Số dùng một lần của người gửi tăng thêm một đơn vị.

### Thuộc tính <a href="#attributes" id="attributes"></a>

| Thuộc tính         | Mô tả                                     | Loại                                                                                                                                                                                                                                                                                                                                    |
| ------------------ | ----------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| type               | uint8 (Go)                                | Loại TxTypeFeeDelegatedCancelWithRatio. Thuộc tính này phải là 0x3a.                                                                                                                                                                                                                                                                     |
| nonce              | uint64 (Go)                               | Giá trị dùng để định danh duy nhất cho một giao dịch của người gửi. Nếu hai giao dịch có cùng một giá trị số dùng một lần do người gửi tạo ra, chỉ có một giao dịch sẽ được thực thi.                                                                                                                                                    |
| giá gas            | \*big.Int (Go)                            | Đơn giá của gas tính bằng `peb` mà người gửi sẽ dùng để thanh toán phí giao dịch. Số tiền phí giao dịch được tính theo công thức `gas` \* `gasPrice`. Ví dụ: Nếu giao dịch tốn 10 đơn vị gas và gasPrice là 10^18, phí giao dịch sẽ là 10 KLAY. Hãy xem [Đơn vị của KLAY](/content/klaytn/design/klaytn-native-coin-klay#units-of-klay). |
| gas                | uint64 (Go)                               | Giá trị phí giao dịch tối đa mà giao dịch được phép sử dụng.                                                                                                                                                                                                                                                                             |
| từ                 | common.Address (Go)                       | Địa chỉ của người gửi. Để biết thêm chi tiết, hãy xem [Xác thực chữ ký của giao dịch](/content/klaytn/design/transactions#signature-validation-of-transactions).                                                                                                                                                                         |
| feeRatio           | uint8 (Go)                                | Tỷ lệ phí của người trả phí. Khoảng hợp lệ là từ 1 đến 99. Số không (0) không được chấp nhận. Số từ 100 trở lên cũng không được chấp nhận.                                                                                                                                                                                               |
| txSignatures       | \[]{\*big.Int, \*big.Int, \*big.Int} (Go) | Chữ ký của người gửi. Để biết thêm chi tiết, hãy xem [Xác thực chữ ký của giao dịch](/content/klaytn/design/transactions#signature-validation-of-transactions).                                                                                                                                                                          |
| feePayer           | common.Address (Go)                       | Địa chỉ của người trả phí.                                                                                                                                                                                                                                                                                                               |
| feePayerSignatures | \[]{\*big.Int, \*big.Int, \*big.Int} (Go) | Chữ ký của người trả phí.                                                                                                                                                                                                                                                                                                                |

### Mã hóa RLP cho chữ ký của người gửi <a href="#rlp-encoding-for-signature-of-the-sender" id="rlp-encoding-for-signature-of-the-sender"></a>

Để tạo chữ ký của người gửi, quá trình tuần tự hóa RLP phải diễn ra như sau:

```javascript
SigRLP = encode([encode([type, nonce, gasPrice, gas, from, feeRatio]), chainid, 0, 0])
SigHash = keccak256(SigRLP)
Signature = sign(SigHash, <the sender's private key>)
```

### Mã hóa RLP cho chữ ký của người trả phí <a href="#rlp-encoding-for-signature-of-the-fee-payer" id="rlp-encoding-for-signature-of-the-fee-payer"></a>

Để tạo chữ ký của người trả phí, quá trình tuần tự hóa RLP phải diễn ra như sau:

```javascript
SigFeePayerRLP = encode([encode([type, nonce, gasPrice, gas, from, feeRatio]), feePayer, chainid, 0, 0])
SigFeePayerHash = keccak256(SigFeePayerRLP)
SignatureFeePayer = sign(SigFeePayerHash, <the fee payer's private key>)
```

### Mã hóa RLP cho SenderTxHash <a href="#rlp-encoding-for-sendertxhash" id="rlp-encoding-for-sendertxhash"></a>

Để tạo một SenderTxHash, quá trình tuần tự hóa RLP phải diễn ra như sau:

```javascript
txSignatures (a single signature) = [[v, r, s]]
txSignatures (two signatures) = [[v1, r1, s1], [v2, r2, s2]]
SenderTxHashRLP = type + encode([nonce, gasPrice, gas, from, feeRatio, txSignatures])
SenderTxHash = keccak256(SenderTxHashRLP)
```

### Mã hóa RLP cho hàm băm giao dịch <a href="#rlp-encoding-for-transaction-hash" id="rlp-encoding-for-transaction-hash"></a>

Để tạo một hàm băm giao dịch, quá trình tuần tự hóa RLP phải diễn ra như sau:

```javascript
txSignatures (a single signature) = [[v, r, s]]
txSignatures (two signatures) = [[v1, r1, s1], [v2, r2, s2]]
feePayerSignatures (a single signature) = [[v, r, s]]
feePayerSignatures (two signatures) = [[v1, r1, s1], [v2, r2, s2]]
TxHashRLP = type + encode([nonce, gasPricke, gas, from, feeRatio, txSignatures, feePayer, feePayerSignatures])
TxHash = keccak256(TxHashRLP)
```

### Mã hóa RLP (Ví dụ) <a href="#rlp-encoding-example" id="rlp-encoding-example"></a>

Phần dưới đây cho thấy kết quả của quá trình tuần tự hóa RLP và đối tượng giao dịch:

```javascript
ChainID 0x1
PrivateKey 0x45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8
PublicKey.X 0x3a514176466fa815ed481ffad09110a2d344f6c9b78c1d14afc351c3a51be33d
PublicKey.Y 0x8072e77939dc03ba44790779b7a1025baf3003f6732430e20cd9b76d953391b3
SigRLP 0xe4a0df3a8204d219830f424094a94f5374fce5edbc8e2a8697c15331677e6ebf0b1e018080
SigHash 0xeccd1585e8e105bc034a72190c3e9312b5407736686aa0d34b1ad75320871014
Signature f845f84326a072efa47960bef40b536c72d7e03ceaf6ca5f6061eb8a3eda3545b1a78fe52ef5a062006ddaf874da205f08b3789e2d014ae37794890fc2e575bf75201563a24ba9
FeePayerPrivateKey 0xb9d5558443585bca6f225b935950e3f6e69f9da8a5809a83f51c3365dff53936
FeePayerPublicKey.X 0x327434d4cfc66ef8857d431419e9deebdc53a3e415edcc55382e2d417b8dd102
FeePayerPublicKey.Y 0x65fc97045707faf7b8f81ac65089d4cc71f69ad0bf1bc8559bc24f13fc284ced
SigRLPFeePayer 0xf839a0df3a8204d219830f424094a94f5374fce5edbc8e2a8697c15331677e6ebf0b1e945a0043070275d9f6054307ee7348bd660849d90f018080
SigHashFeePayer 0xf71b0b22d72ef59a063a865ee844e1ba0a103d707f06fb7013b3372ed169c705
SignatureFeePayer f845f84326a06ba5ef20c3049323fc94defe14ca162e28b86aa64f7cf497ac8a5520e9615614a04a0a0fc61c10b416759af0ce4ce5c09ca1060141d56d958af77050c9564df6bf
TxHashRLP 0x3af8c18204d219830f424094a94f5374fce5edbc8e2a8697c15331677e6ebf0b1ef845f84326a072efa47960bef40b536c72d7e03ceaf6ca5f6061eb8a3eda3545b1a78fe52ef5a062006ddaf874da205f08b3789e2d014ae37794890fc2e575bf75201563a24ba9945a0043070275d9f6054307ee7348bd660849d90ff845f84326a06ba5ef20c3049323fc94defe14ca162e28b86aa64f7cf497ac8a5520e9615614a04a0a0fc61c10b416759af0ce4ce5c09ca1060141d56d958af77050c9564df6bf
TxHash 63604ebf68bfee51b2e3f54ddb2f19f9ea72d32b3fc70877324531ecda25817a
SenderTxHashRLP 0x3af8658204d219830f424094a94f5374fce5edbc8e2a8697c15331677e6ebf0b1ef845f84326a072efa47960bef40b536c72d7e03ceaf6ca5f6061eb8a3eda3545b1a78fe52ef5a062006ddaf874da205f08b3789e2d014ae37794890fc2e575bf75201563a24ba9
SenderTxHash c0818be4cffbacfe29be1134e0267e10fd1afb6571f4ccc95dcc67a788bab5e7

    TX(63604ebf68bfee51b2e3f54ddb2f19f9ea72d32b3fc70877324531ecda25817a)
    Type:          TxTypeFeeDelegatedCancelWithRatio
    From:          0xa94f5374Fce5edBC8E2a8697C15331677e6EbF0B
    Nonce:         1234
    GasPrice:      0x19
    GasLimit:      0xf4240
    Signature:     [{"V":"0x26","R":"0x72efa47960bef40b536c72d7e03ceaf6ca5f6061eb8a3eda3545b1a78fe52ef5","S":"0x62006ddaf874da205f08b3789e2d014ae37794890fc2e575bf75201563a24ba9"}]
    FeePayer:      0x5A0043070275d9f6054307Ee7348bD660849D90f
    FeeRatio:      30
    FeePayerSig:   [{"V":"0x26","R":"0x6ba5ef20c3049323fc94defe14ca162e28b86aa64f7cf497ac8a5520e9615614","S":"0x4a0a0fc61c10b416759af0ce4ce5c09ca1060141d56d958af77050c9564df6bf"}]
    Hex:           3af8c18204d219830f424094a94f5374fce5edbc8e2a8697c15331677e6ebf0b1ef845f84326a072efa47960bef40b536c72d7e03ceaf6ca5f6061eb8a3eda3545b1a78fe52ef5a062006ddaf874da205f08b3789e2d014ae37794890fc2e575bf75201563a24ba9945a0043070275d9f6054307ee7348bd660849d90ff845f84326a06ba5ef20c3049323fc94defe14ca162e28b86aa64f7cf497ac8a5520e9615614a04a0a0fc61c10b416759af0ce4ce5c09ca1060141d56d958af77050c9564df6bf
```

### Kết quả đầu ra RPC (Example) <a href="#rpc-output-example" id="rpc-output-example"></a>

Phần dưới đây cho thấy một đối tượng giao dịch được trả về qua JSON RPC.

```javascript
{
  "blockHash": "0x82983fe294d286e76486760e6904369285554e1744af16786c2393a956fb4ec4",
  "blockNumber": "0x2",
  "contractAddress": null,
  "feePayer": "0x029fdce0457db02f05c4be9f67b7115cb8ea15ca",
  "feePayerSignatures": [
    {
      "V": "0x25",
      "R": "0x26c8b5038e9f7ff580f3323b8a06b6eb1b6ab13cac11c30de6c9b64230bdb992",
      "S": "0x6c4be67ace8551237e675da2b7b32ec2d7d7e07abf2eb299ebec6cc444460e13"
    }
  ],
  "feeRatio": "0x58",
  "from": "0x0fcda0f2efbe1b4e61b487701ce4f2f8abc3723d",
  "gas": "0x174876e800",
  "gasPrice": "0x0",
  "gasUsed": "0x8ca0",
  "nhật ký": [],
  "nhật kýBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
  "nonce": "0x12",
  "senderTxHash": "0xc9d2f558f6883bfea5113ce900499354fcb0004ff901dec51db7a5d80c3a7868",
  "signatures": [
    {
      "V": "0x26",
      "R": "0x88a484d1cc59824e05b933348df6ebe7b82ac68766a85e2aa5636c136ee2834c",
      "S": "0x104fee953e1a015f26b35da57acf15aa01eb5c6c0e79965200c3fe813003a4fe"
    }
  ],
  "trạng thái": "0x1",
  "transactionHash": "0x50c6840fee3297a8ff745025cb4fd27a7e662395620ad615458ea22034f37f6c",
  "transactionIndex": "0xb",
  "type": "TxTypeFeeDelegatedCancelWithRatio",
  "typeInt": 58
}
```

## TxTypeFeeDelegatedChainDataAnchoringWithRatio <a href="#txtypefeedelegatedchaindataanchoringwithratio" id="txtypefeedelegatedchaindataanchoringwithratio"></a>

TxTypeFeeDelegatedChainDataAnchoringWithRatio là một giao dịch có phí ủy thác kèm theo tỷ lệ, dùng để neo dữ liệu chuỗi dịch vụ vào chuỗi chính của Klaytn. Các chuỗi dịch vụ gửi định kỳ loại giao dịch này đến chuỗi chính Klaytn để đảm bảo tính bảo mật và độ tin cậy của dữ liệu. Để biết thêm chi tiết về việc neo dữ liệu, hãy xem [Neo](/content/installation-guide/deployment/service-chain/references/anchoring). Vì đây cũng là một giao dịch ủy có phí ủy thác với tỷ lệ cho trước, người trả phí chỉ phải thanh toán phần nhất định của khoản phí giao dịch dựa theo tỷ lệ cho trước, đồng thời người gửi sẽ thanh toán phần còn lại. Lưu ý rằng giao dịch này không được phép gửi qua RPC. Hiện tại, giao dịch này được thực thi qua các kênh p2p riêng tư vì lý do bảo mật. Giao dịch này không làm thay đổi trạng thái của chuỗi khối Klaytn, ngoại trừ việc số dùng một lần của người gửi tăng lên một đơn vị.

### Thuộc tính <a href="#attributes" id="attributes"></a>

| Thuộc tính         | Loại                                     | Mô tả                                                                                                                                                                                                                                                                                                                                    |
| ------------------ | ----------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| type               | uint8 (Go)                                | Loại TxTypeFeeDelegatedChainDataAnchoringWithRatio. Thuộc tính này phải là 0x4a.                                                                                                                                                                                                                                                         |
| nonce              | uint64 (Go)                               | Giá trị dùng để định danh duy nhất cho một giao dịch của người gửi. Nếu hai giao dịch có cùng một giá trị số dùng một lần do người gửi tạo ra, chỉ có một giao dịch sẽ được thực thi.                                                                                                                                                    |
| giá gas            | \*big.Int (Go)                            | Đơn giá của gas tính bằng `peb` mà người gửi sẽ dùng để thanh toán phí giao dịch. Số tiền phí giao dịch được tính theo công thức `gas` \* `gasPrice`. Ví dụ: Nếu giao dịch tốn 10 đơn vị gas và gasPrice là 10^18, phí giao dịch sẽ là 10 KLAY. Hãy xem [Đơn vị của KLAY](/content/klaytn/design/klaytn-native-coin-klay#units-of-klay). |
| gas                | uint64 (Go)                               | Giá trị phí giao dịch tối đa mà giao dịch được phép sử dụng.                                                                                                                                                                                                                                                                             |
| từ                 | common.Address (Go)                       | Địa chỉ của người gửi. Để biết thêm chi tiết, hãy xem [Xác thực chữ ký của giao dịch](/content/klaytn/design/transactions#signature-validation-of-transactions).                                                                                                                                                                         |
| feeRatio           | uint8 (Go)                                | Tỷ lệ phí của người trả phí. Khoảng hợp lệ là từ 1 đến 99. Số không (0) không được chấp nhận. Số từ 100 trở lên cũng không được chấp nhận.                                                                                                                                                                                               |
| nhập               | \[]byte (Go)                              | Dữ liệu của chuỗi dịch vụ.                                                                                                                                                                                                                                                                                                               |
| txSignatures       | \[]{\*big.Int, \*big.Int, \*big.Int} (Go) | Chữ ký của người gửi. Để biết thêm chi tiết, hãy xem [Xác thực chữ ký của giao dịch](/content/klaytn/design/transactions#signature-validation-of-transactions).                                                                                                                                                                          |
| feePayer           | common.Address (Go)                       | Địa chỉ của người trả phí.                                                                                                                                                                                                                                                                                                               |
| feePayerSignatures | \[]{\*big.Int, \*big.Int, \*big.Int} (Go) | Chữ ký của người trả phí.                                                                                                                                                                                                                                                                                                                |

### Mã hóa RLP cho chữ ký của người gửi <a href="#rlp-encoding-for-signature-of-the-sender" id="rlp-encoding-for-signature-of-the-sender"></a>

Để tạo chữ ký của người gửi, quá trình tuần tự hóa RLP phải diễn ra như sau:

```javascript
SigRLP = encode([encode([type, nonce, gasPrice, gas, from, anchoredData, feeRatio]), chainid, 0, 0])
SigHash = keccak256(SigRLP)
Signature = sign(SigHash, <private key>)
```

### Mã hóa RLP cho chữ ký của người trả phí <a href="#rlp-encoding-for-signature-of-the-fee-payer" id="rlp-encoding-for-signature-of-the-fee-payer"></a>

Để tạo chữ ký của người trả phí, quá trình tuần tự hóa RLP phải diễn ra như sau:

```javascript
SigFeePayerRLP = encode([encode([type, nonce, gasPrice, gas, from, anchoredData, feeRatio]), feePayer, chainid, 0, 0])
SigFeePayerHash = keccak256(SigFeePayerRLP)
SignatureFeePayer = sign(SigFeePayerHash, <the fee payer's private key>)
```

### Mã hóa RLP cho SenderTxHash <a href="#rlp-encoding-for-sendertxhash" id="rlp-encoding-for-sendertxhash"></a>

Để tạo một SenderTxHash, quá trình tuần tự hóa RLP phải diễn ra như sau:

```javascript
txSignatures (a single signature) = [[v, r, s]]
txSignatures (two signatures) = [[v1, r1, s1], [v2, r2, s2]]
SenderTxHashRLP = type + encode([nonce, gasPrice, gas, from, anchoredData, feeRatio, txSignatures])
SenderTxHash = keccak256(SenderTxHashRLP)
```

### Mã hóa RLP cho hàm băm giao dịch <a href="#rlp-encoding-for-transaction-hash" id="rlp-encoding-for-transaction-hash"></a>

Để tạo một hàm băm giao dịch, quá trình tuần tự hóa RLP phải diễn ra như sau:

```javascript
txSignatures (a single signature) = [[v, r, s]]
txSignatures (two signatures) = [[v1, r1, s1], [v2, r2, s2]]
feePayerSignatures (a single signature) = [[v, r, s]]
feePayerSignatures (two signatures) = [[v1, r1, s1], [v2, r2, s2]]
TxHashRLP = type + encode([nonce, gasPrice, gas, from, anchoredData, feeRatio, txSignatures, feePayer, feePayerSignatures])
TxHash = keccak256(TxHashRLP)
```

### Mã hóa RLP (Ví dụ) <a href="#rlp-encoding-example" id="rlp-encoding-example"></a>

Phần dưới đây cho thấy kết quả của quá trình tuần tự hóa RLP và đối tượng giao dịch:

```javascript
ChainID 0x01
PrivateKey 0x45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8
PublicKey.X 0x3a514176466fa815ed481ffad09110a2d344f6c9b78c1d14afc351c3a51be33d
PublicKey.Y 0x8072e77939dc03ba44790779b7a1025baf3003f6732430e20cd9b76d953391b3
SigRLP 0xf8dcb8d7f8d54a128505d21dba0085174876e80094a94f5374fce5edbc8e2a8697c15331677e6ebf0bb8aff8ad80b8aaf8a8a00000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000001a00000000000000000000000000000000000000000000000000000000000000002a00000000000000000000000000000000000000000000000000000000000000003a0000000000000000000000000000000000000000000000000000000000000000405800658018080
SigHash 0xd79dbb964bee2d3807e214a247141a1fcb066a67de99e90750aac4a2a0b776de
Signature 0xf845f84326a0c612a243bcb3b98958e9cce1a0bc0e170291b33a7f0dbfae4b36dafb5806797da00c734423492ecc21cc53238147c359676fcec43fcc2a0e021d87bb1da49f0abf
FeePayerPrivateKey 0xb9d5558443585bca6f225b935950e3f6e69f9da8a5809a83f51c3365dff53936
FeePayerPublicKey.X 0x327434d4cfc66ef8857d431419e9deebdc53a3e415edcc55382e2d417b8dd102
FeePayerPublicKey.Y 0x65fc97045707faf7b8f81ac65089d4cc71f69ad0bf1bc8559bc24f13fc284ced
SigRLPFeePayer 0xf8f1b8d7f8d54a128505d21dba0085174876e80094a94f5374fce5edbc8e2a8697c15331677e6ebf0bb8aff8ad80b8aaf8a8a00000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000001a00000000000000000000000000000000000000000000000000000000000000002a00000000000000000000000000000000000000000000000000000000000000003a00000000000000000000000000000000000000000000000000000000000000004058006589433f524631e573329a550296f595c820d6c65213f018080
SigHashFeePayer 0xa824ff743912239d0665d2fd43a66d57138c92834e9d338b66bcca4a0bee8fbd
SignatureFeePayer 0xf845f84325a0a3e40598b67e2bcbaa48fdd258b9d1dcfcc9cc134972560ba042430078a769a5a06707ea362e588e4e5869cffcd5a058749d823aeff13eb95dc1146faff561df32
TxHashRLP 0x4af90177128505d21dba0085174876e80094a94f5374fce5edbc8e2a8697c15331677e6ebf0bb8aff8ad80b8aaf8a8a00000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000001a00000000000000000000000000000000000000000000000000000000000000002a00000000000000000000000000000000000000000000000000000000000000003a0000000000000000000000000000000000000000000000000000000000000000405800658f845f84326a0c612a243bcb3b98958e9cce1a0bc0e170291b33a7f0dbfae4b36dafb5806797da00c734423492ecc21cc53238147c359676fcec43fcc2a0e021d87bb1da49f0abf9433f524631e573329a550296f595c820d6c65213ff845f84325a0a3e40598b67e2bcbaa48fdd258b9d1dcfcc9cc134972560ba042430078a769a5a06707ea362e588e4e5869cffcd5a058749d823aeff13eb95dc1146faff561df32
TxHash 0xc01a7c3ece18c115b58d7747669ec7c31ec5ab031a88cb49ad85a31f6dbbf915
SenderTxHashRLP 0x4af9011b128505d21dba0085174876e80094a94f5374fce5edbc8e2a8697c15331677e6ebf0bb8aff8ad80b8aaf8a8a00000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000001a00000000000000000000000000000000000000000000000000000000000000002a00000000000000000000000000000000000000000000000000000000000000003a0000000000000000000000000000000000000000000000000000000000000000405800658f845f84326a0c612a243bcb3b98958e9cce1a0bc0e170291b33a7f0dbfae4b36dafb5806797da00c734423492ecc21cc53238147c359676fcec43fcc2a0e021d87bb1da49f0abf
SenderTxHash 0xa0670c01fe39feb2d2442adf7df1957ade3c5abcde778fb5edf99c80c06aa53c

    TX(c01a7c3ece18c115b58d7747669ec7c31ec5ab031a88cb49ad85a31f6dbbf915)
    Type:          TxTypeFeeDelegatedChainDataAnchoringWithRatio
    From:          0xa94f5374Fce5edBC8E2a8697C15331677e6EbF0B
    Nonce:         18
    GasPrice:      0x5d21dba00
    GasLimit:      0x174876e800
    AnchoredData:  f8ad80b8aaf8a8a00000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000001a00000000000000000000000000000000000000000000000000000000000000002a00000000000000000000000000000000000000000000000000000000000000003a00000000000000000000000000000000000000000000000000000000000000004058006
    Signature:     [{"V":"0x26","R":"0xc612a243bcb3b98958e9cce1a0bc0e170291b33a7f0dbfae4b36dafb5806797d","S":"0xc734423492ecc21cc53238147c359676fcec43fcc2a0e021d87bb1da49f0abf"}]
    FeePayer:      0x33f524631e573329a550296F595c820D6c65213f
    FeeRatio:      88
    FeePayerSig:   [{"V":"0x25","R":"0xa3e40598b67e2bcbaa48fdd258b9d1dcfcc9cc134972560ba042430078a769a5","S":"0x6707ea362e588e4e5869cffcd5a058749d823aeff13eb95dc1146faff561df32"}]
    Hex:           4af90177128505d21dba0085174876e80094a94f5374fce5edbc8e2a8697c15331677e6ebf0bb8aff8ad80b8aaf8a8a00000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000001a00000000000000000000000000000000000000000000000000000000000000002a00000000000000000000000000000000000000000000000000000000000000003a0000000000000000000000000000000000000000000000000000000000000000405800658f845f84326a0c612a243bcb3b98958e9cce1a0bc0e170291b33a7f0dbfae4b36dafb5806797da00c734423492ecc21cc53238147c359676fcec43fcc2a0e021d87bb1da49f0abf9433f524631e573329a550296f595c820d6c65213ff845f84325a0a3e40598b67e2bcbaa48fdd258b9d1dcfcc9cc134972560ba042430078a769a5a06707ea362e588e4e5869cffcd5a058749d823aeff13eb95dc1146faff561df32
```

### Kết quả đầu ra RPC (Example) <a href="#rpc-output-example" id="rpc-output-example"></a>

Phần dưới đây cho thấy một đối tượng giao dịch được trả về qua JSON RPC.

```javascript
{
    "blockHash": "0xee6c72b7d99019a941b47d77507abe015c3f00d3ff9122a2eec33d846107b842",
    "blockNumber": "0x2",
    "contractAddress": null,
    "feePayer": "0x33f524631e573329a550296f595c820d6c65213f",
    "feePayerSignatures": [
        {
            "V": "0x25",
            "R": "0xa3e40598b67e2bcbaa48fdd258b9d1dcfcc9cc134972560ba042430078a769a5",
            "S": "0x6707ea362e588e4e5869cffcd5a058749d823aeff13eb95dc1146faff561df32"
        }
    ],
    "feeRatio": "0x58",
    "from": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
    "gas": "0x174876e800",
    "gasPrice": "0x5d21dba00",
    "gasUsed": "0xd0fc",
    "input": "0xf8ad80b8aaf8a8a00000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000001a00000000000000000000000000000000000000000000000000000000000000002a00000000000000000000000000000000000000000000000000000000000000003a00000000000000000000000000000000000000000000000000000000000000004058006",
    "nhật ký": [],
    "nhật kýBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
    "nonce": "0x12",
    "senderTxHash": "0xa0670c01fe39feb2d2442adf7df1957ade3c5abcde778fb5edf99c80c06aa53c",
    "signatures": [
        {
            "V": "0x26",
            "R": "0xc612a243bcb3b98958e9cce1a0bc0e170291b33a7f0dbfae4b36dafb5806797d",
            "S": "0xc734423492ecc21cc53238147c359676fcec43fcc2a0e021d87bb1da49f0abf"
        }
    ],
    "trạng thái": "0x1",
    "transactionHash": "0xc01a7c3ece18c115b58d7747669ec7c31ec5ab031a88cb49ad85a31f6dbbf915",
    "transactionIndex": "0xb",
    "type": "TxTypeFeeDelegatedChainDataAnchoringWithRatio",
    "typeInt": 74
}
```

\[AccountKey]: ../tài khoảns.md#tài khoản-key


# Ethereum

Klaytn cung cấp các loại giao dịch được bọc nhằm hỗ trợ khả năng tương thích với Ethereum. Các loại giao dịch Ethereum trong Klaytn có cùng các thuộc tính và sơ đồ mã hóa RLP với thiết kể của Ethereum, ngoại trừ dấu phân tách loại một byte có tên là `EthereumTxTypeEnvelope`. Vì thế, người dùng có thể triển khai thành công các giao dịch được tạo bằng công cụ phát triển Ethereum trên Klaytn. Dấu phân tách loại cũng được bỏ qua khi người dùng sử dụng API không gian tên `eth` để họ có thể sử dụng Klaytn như Ethereum. Khi sử dụng các API không gian tên `klay`, người dùng có thể triển khai và truy xuất các giao dịch có định dạng Ethereum như một loại giao dịch Klaytn và không bị nhầm lẫn với các loại giao dịch Klaytn hiện có.

## EthereumTxTypeEnvelope <a href="#ethereumtxtypeenvelope" id="ethereumtxtypeenvelope"></a>

EthereumTxTypeEnvelope là tiền tố một byte cho các giao dịch thô, biểu thị các loại giao dịch Ethereum. Ethereum đã ứng dụng sơ đồ loại giao dịch có thể mở rộng từ [EIP-2718](https://eips.ethereum.org/EIPS/eip-2718) và sử dụng một hệ thống đánh số phân loại có xung đột với Klaytn. Để giải quyết xung đột giữa hai sơ đồ loại giao dịch khác nhau, Klaytn đã giới thiệu `EthereumTxTypeEnvelope`, cho phép phân tách và mở rộng các loại giao dịch Ethereum trong tương lai.

`EthereumTxTypeEnvelope` là một dấu phân tách loại bổ sung và chỉ được sử dụng cho các giao dịch thô và đánh số phân loại. Nó không được sử dụng cho hàm băm giao dịch hoặc hàm băm chữ ký. Vì mục đích đó, `EthereumTransactionType`, như được định nghĩa trong EIP, sẽ được sử dụng.

* EthereumTxTypeEnvelope: `0x78`
* TxHashRLP : EthereumTransactionType || TransactionPayload
* RawTransaction : EthereumTxTypeEnvelope || Loại giao dịch Ethereum || TransactionPayload

## TxTypeEthereumAccessList <a href="#txtypeethereumaccesslist" id="txtypeethereumaccesslist"></a>

`TxTypeEthereumAccessList` đại diện cho một loại giao dịch Ethereum được chỉ định trong [EIP-2930](https://eips.ethereum.org/EIPS/eip-2930). Loại giao dịch này chứa một danh sách quyền truy cập, một danh sách các địa chỉ và khóa lưu trữ mà giao dịch cần phải truy cập. Vì loại giao dịch này tồn tại để hỗ trợ khả năng tương thích, nó chỉ hoạt động với các EOA liên kết với \[AccountKeyLegacy]. Các EOA liên kết với loại khóa tài khoản khác sẽ sử dụng những loại giao dịch khác như `TxTypeValueTransfer`, `TxTypeSmartContractExecution`, v.v. Loại giao dịch này có thể tạo tài khoản, chuyển token, triển khai/thực thi hợp đồng thông minh hoặc kết hợp những hoạt động vừa nêu.

{% hint style="success" %}
LƯU Ý: Mạng Klaytn có thể xử lý loại giao dịch này sau `EthTxTypeCompatibleBlock`
{% endhint %}

{% hint style="success" %}
LƯU Ý: Loại giao dịch này chỉ hỗ trợ định dạng của loại giao dịch Ethereum. Khác với [EIP-2930](https://eips.ethereum.org/EIPS/eip-2930), việc sử dụng danh sách quyền truy cập không mang lại lợi ích về mặt phí giao dịch.
{% endhint %}

### Thuộc tính <a href="#attributes" id="attributes"></a>

| Thuộc tính | type                  | Mô tả                                                                                                                                                                                                                                                                                   |
| ---------- | --------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| type       | uint8 (Go)            | Loại `TxTypeEthereumAccessList` là sự kết nối của `EthereumTxTypeEnvelope` và `EthereumTransactionType`. Thuộc tính này phải là 0x7801.                                                                                                                                                 |
| chainId    | \*big.Int (Go)        | ID chuỗi đích.                                                                                                                                                                                                                                                                          |
| nonce      | uint64 (Go)           | Giá trị dùng để định danh duy nhất cho một giao dịch của người gửi. Nếu hai giao dịch có cùng một giá trị số dùng một lần do người gửi tạo ra, chỉ có một giao dịch sẽ được thực thi.                                                                                                   |
| giá gas    | \*big.Int (Go)        | Hệ số nhân để tính toán số lượng token mà người gửi sẽ thanh toán. Lượng token mà người gửi sẽ thanh toán được tính theo công thức `gas` \* `gasPrice`. Ví dụ: Người gửi sẽ thanh toán khoản phí giao dịch là 10 KLAY nếu gas bằng 10 và gasPrice là 10^18. Hãy xem \[Đơn vị của KLAY]. |
| gas        | uint64 (Go)           | Giá trị phí giao dịch tối đa mà giao dịch được phép sử dụng.                                                                                                                                                                                                                            |
| đến        | \*common.Address (Go) | Địa chỉ tài khoản sẽ nhận giá trị được chuyển.                                                                                                                                                                                                                                          |
| giá trị    | \*big.Int (Go)        | Số lượng KLAY tính bằng `peb` sẽ được chuyển.                                                                                                                                                                                                                                           |
| data       | \[]byte (Go)          | Dữ liệu được gắn kèm giao dịch, dùng để thực thi giao dịch.                                                                                                                                                                                                                             |
| accessList | type.AccessList (Go)  | Một danh sách gồm các địa chỉ và khóa lưu trữ bao gồm \[]\(common.Address, \[]common.Hash).                                                                                                                                                                                             |
| v, r, s    | \*big.Int (Go)        | Chữ ký mật mã được tạo bởi người gửi để cho phép người nhận lấy được địa chỉ của người gửi.                                                                                                                                                                                             |

### Mã hóa RLP cho chữ ký <a href="#rlp-encoding-for-signature" id="rlp-encoding-for-signature"></a>

Để tạo chữ ký cho loại giao dịch này, việc tuần tự hóa RLP phải được thực hiện như sau:

{% hint style="success" %}
LƯU Ý: Loại giao dịch này phải được ký bằng London Signer
{% endhint %}

```javascript
SigRLP = EthereumTransactionType || encode([chainId, nonce, gasPrice, gasLimit, to, value, data, accessList])
SigHash = keccak256(SigRLP)
Signature = sign(SigHash, <private key>)
```

### Mã hóa RLP cho SenderTxHash <a href="#rlp-encoding-for-sendertxhash" id="rlp-encoding-for-sendertxhash"></a>

Để lấy `SenderTxHash` cho loại giao dịch này, việc tuần tự hóa RLP được thực hiện như sau:

```javascript
SenderTxHashRLP = EthereumTransactionType || encode([chainId, nonce, gasPrice, gasLimit, to, value, data, accessList, v, r, s])
SenderTxHash = keccak256(SenderTxHashRLP)
Signature = sign(SenderTxHash, <private key>)
```

### Mã hóa RLP cho hàm băm giao dịch <a href="#rlp-encoding-for-transaction-hash" id="rlp-encoding-for-transaction-hash"></a>

Để tạo một hàm băm giao dịch, việc tuần tự hóa RLP được thực hiện nhu sau:

```javascript
TxHashRLP = EthereumTransactionType || encode([chainId, nonce, gasPrice, gasLimit, to, value, data, accessList, v, r, s])
TxHash = keccak256(TxHashRLP)
```

### Giao dịch thô <a href="#raw-transaction" id="raw-transaction"></a>

```javascript
RawTx = EthereumTxTypeEnvelope || EthereumTransactionType || encode([chainId, nonce, gasPrice, gasLimit, to, value, data, accessList, v, r, s])
```

### Mã hóa RLP (Ví dụ) <a href="#rlp-encoding-example" id="rlp-encoding-example"></a>

Phần dưới đây cho thấy kết quả của quá trình tuần tự hóa RLP và đối tượng giao dịch:

```javascript
    TX(3a3ab67168de40b1f8a2141a70a4e2f551f90d7814b2fbcb3ac99ad8d8d0b641)
    Contract: false
    Chaind:   0x2
    From:     a94f5374fce5edbc8e2a8697c15331677e6ebf0b
    To:       7b65b75d204abed71587c9e519a89277766ee1d0
    Nonce:    1234
    GasPrice: 0x19
    GasLimit  0xf4240
    Value:    0xa
    Data:     0x31323334
    AccessList: [{0000000000000000000000000000000000000001 [0000000000000000000000000000000000000000000000000000000000000000]}]
    V:        0x1
    R:        0xbfc80a874c43b71b67c68fa5927d1443407f31aef4ec6369bbecdb76fc39b0c0
    S:        0x193e62c1dd63905aee7073958675dcb45d78c716a9a286b54a496e82cb762f26
    Hex:      7801f8a1028204d219830f4240947b65b75d204abed71587c9e519a89277766ee1d00a8431323334f838f7940000000000000000000000000000000000000001e1a0000000000000000000000000000000000000000000000000000000000000000001a0bfc80a874c43b71b67c68fa5927d1443407f31aef4ec6369bbecdb76fc39b0c0a0193e62c1dd63905aee7073958675dcb45d78c716a9a286b54a496e82cb762f26


```

### Kết quả đầu ra RPC (Example) <a href="#rpc-output-example" id="rpc-output-example"></a>

Phần dưới đây cho thấy một đối tượng giao dịch được trả về qua JSON RPC.

Kết quả trả về của `eth_getTransactionByHash`

```javascript
{
  "blockHash": "0x7bd7e8a92ecaa5781a15a8b6fff589f8ac8a79325b517a1ba5d5f2f3d7af1b00",
  "blockNumber": "0x1c8f4b",
  "from": "0x5618e15ec2916bbe6cf2cce20ce31e61d6062cac",
  "gas": "0x174876e800",
  "gasPrice": "0x5d21dba00",
  "hash": "0x3f67e48c2090f560234f555cd4edf7853b6327aa9a6a795be1efe3f360dac118",
  "input": "0x1122",
  "nonce": "0x11",
  "to": "0x5dce87b5bfcde54023811b168dc97a9f10913957",
  "transactionIndex": "0x0",
  "value": "0x186a0",
  "type": "0x1",
  "accessList": [
      {
          "address": "0x0000000000000000000000000000000000000001",
          "storageKeys": [
              "0x0000000000000000000000000000000000000000000000000000000000000000"
          ]
      }
  ],
  "chainId": "0x2710",
  "v": "0x1",
  "r": "0xebb2d2144293c257e27aaa1d22156f322b0d2d7385257f186c117899d791f174",
  "s": "0x5cea970287c9f0f9754050a552c458c066d8f3b3e4639f561b22ce4cb7553ac0"
}
```

Kết quả trả về của `klay_getTransactionByHash`

```javascript
{
  "accessList": [
      {
          "address": "0x0000000000000000000000000000000000000001",
          "storageKeys": [
              "0x0000000000000000000000000000000000000000000000000000000000000000"
          ]
      }
  ],
  "blockHash": "0x7bd7e8a92ecaa5781a15a8b6fff589f8ac8a79325b517a1ba5d5f2f3d7af1b00",
  "blockNumber": "0x1c8f4b",
  "chainID": "0x2710",
  "from": "0x5618e15ec2916bbe6cf2cce20ce31e61d6062cac",
  "gas": "0x174876e800",
  "gasPrice": "0x5d21dba00",
  "hash": "0x3f67e48c2090f560234f555cd4edf7853b6327aa9a6a795be1efe3f360dac118",
  "input": "0x1122",
  "nonce": "0x11",
  "senderTxHash": "0x3f67e48c2090f560234f555cd4edf7853b6327aa9a6a795be1efe3f360dac118",
  "signatures": [
      {
          "V": "0x1",
          "R": "0xebb2d2144293c257e27aaa1d22156f322b0d2d7385257f186c117899d791f174",
          "S": "0x5cea970287c9f0f9754050a552c458c066d8f3b3e4639f561b22ce4cb7553ac0"
      }
  ],
  "to": "0x5dce87b5bfcde54023811b168dc97a9f10913957",
  "transactionIndex": "0x0",
  "type": "TxTypeEthereumAccessList",
  "typeInt": 30721,
  "value": "0x186a0"
}
```

## TxTypeEthereumDynamicFee <a href="#txtypeethereumdynamicfee" id="txtypeethereumdynamicfee"></a>

`TxTypeEthereumDynamicFee` đại diện cho một loại giao dịch Ethereum được chỉ định trong [EIP-1559](https://eips.ethereum.org/EIPS/eip-1559). Loại giao dịch này chứa `gasTipCap` và `gasFeeCap` thay vì `gasPrice`. Vì loại giao dịch này tồn tại để hỗ trợ khả năng tương thích, nó chỉ hoạt động với các EOA liên kết với \[AccountKeyLegacy]. Các EOA liên kết với loại khóa tài khoản khác sẽ sử dụng những loại giao dịch khác như `TxTypeValueTransfer`, `TxTypeSmartContractExecution`, v.v. Loại giao dịch này có thể tạo tài khoản, chuyển token, triển khai/thực thi hợp đồng thông minh hoặc kết hợp những hoạt động vừa nêu.

{% hint style="success" %}
LƯU Ý: Mạng Klaytn có thể xử lý loại giao dịch này sau `EthTxTypeCompatibleBlock`
{% endhint %}

{% hint style="success" %}
LƯU Ý: Hiện tại, loại giao dịch này chỉ hỗ trợ định dạng của loại giao dịch Ethereum. Khác với [EIP-2930](https://eips.ethereum.org/EIPS/eip-2930), việc sử dụng danh sách quyền truy cập không mang lại lợi ích về mặt phí giao dịch.
{% endhint %}

{% hint style="success" %}
LƯU Ý: Vì Klaytn có giá gas cố định, `gasTipCap` và `gasFeeCap` nên lấy giá gas cho mạng lưới tương ứng, mức giá này là 250 ston vào thời điểm viết bài.
{% endhint %}

### Thuộc tính <a href="#attributes" id="attributes"></a>

| Thuộc tính | Loại                 | Mô tả                                                                                                                                                                                                                                                                                                      |
| ---------- | --------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| type       | uint8 (Go)            | Loại `TxTypeEthereumDynamicFee` là sự kết nối của `EthereumTxTypeEnvelope` và `EthereumTransactionType`. Thuộc tính này phải là `0x7802`.                                                                                                                                                                  |
| chainId    | \*big.Int (Go)        | ID chuỗi đích.                                                                                                                                                                                                                                                                                             |
| nonce      | uint64 (Go)           | Giá trị dùng để định danh duy nhất cho một giao dịch của người gửi. Nếu hai giao dịch có cùng một giá trị số dùng một lần do người gửi tạo ra, chỉ có một giao dịch sẽ được thực thi.                                                                                                                      |
| gasTipCap  | \*big.Int (Go)        | Hệ số nhân để biết mức phí người gửi phải thanh toán ngoài `baseFee`. Vì Klaytn có giá gas cố định, `gasTipCap` và `gasFeeCap` nên lấy giá gas cho mạng lưới tương ứng, mức giá này là 250 ston vào thời điểm viết bài.                                                                                    |
| gasFeeCap  | \*big.Int (Go)        | Hệ số nhân để tính toán số lượng token mà người gửi sẽ thanh toán. Lượng token mà người gửi sẽ thanh toán được tính theo công thức `gas` \* `gasFeeCap`. Vì Klaytn có giá gas cố định, `gasTipCap` và `gasFeeCap` nên lấy giá gas cho mạng lưới tương ứng, mức giá này là 250 ston vào thời điểm viết bài. |
| gas        | uint64 (Go)           | Giá trị phí giao dịch tối đa mà giao dịch được phép sử dụng.                                                                                                                                                                                                                                               |
| đến        | \*common.Address (Go) | Địa chỉ tài khoản sẽ nhận giá trị được chuyển.                                                                                                                                                                                                                                                             |
| giá trị    | \*big.Int (Go)        | Số lượng KLAY tính bằng `peb` sẽ được chuyển.                                                                                                                                                                                                                                                              |
| data       | \[]byte (Go)          | Dữ liệu được gắn kèm giao dịch, dùng để thực thi giao dịch.                                                                                                                                                                                                                                                |
| accessList | type.AccessList (Go)  | Một danh sách gồm các địa chỉ và khóa lưu trữ bao gồm \[]\(common.Address, \[]common.Hash).                                                                                                                                                                                                                |
| v, r, s    | \*big.Int (Go)        | Chữ ký mật mã được tạo bởi người gửi để cho phép người nhận lấy được địa chỉ của người gửi.                                                                                                                                                                                                                |

### Mã hóa RLP cho chữ ký <a href="#rlp-encoding-for-signature" id="rlp-encoding-for-signature"></a>

Để tạo chữ ký cho loại giao dịch này, việc tuần tự hóa RLP phải được thực hiện như sau:

{% hint style="success" %}
LƯU Ý: Loại giao dịch này phải được ký bằng London Signer
{% endhint %}

```javascript
SigRLP = EthereumTransactionType || encode([chainId, nonce, gasTipCap, gasFeeCap, gasLimit, to, value, data, accessList])
SigHash = keccak256(SigRLP)
Signature = sign(SigHash, <private key>)
```

### Mã hóa RLP cho SenderTxHash <a href="#rlp-encoding-for-sendertxhash" id="rlp-encoding-for-sendertxhash"></a>

Để lấy `SenderTxHash` cho loại giao dịch này, việc tuần tự hóa RLP được thực hiện như sau:

```javascript
SenderTxHashRLP = EthereumTransactionType || encode([chainId, nonce, gasTipCap, gasFeeCap, gasLimit, to, value, data, accessList, v, r, s])
SenderTxHash = keccak256(SenderTxHashRLP)
Signature = sign(SenderTxHash, <private key>)
```

### Mã hóa RLP cho hàm băm giao dịch <a href="#rlp-encoding-for-transaction-hash" id="rlp-encoding-for-transaction-hash"></a>

Để lấy một hàm băm giao dịch, việc tuần tự hóa RLP được thực hiện nhu sau:

```javascript
TxHashRLP = EthereumTransactionType || encode([chainId, nonce, gasTipCap, gasFeeCap, gasLimit, to, value, data, accessList, v, r, s])
TxHash = keccak256(TxHashRLP)
```

### Giao dịch thô <a href="#raw-transaction" id="raw-transaction"></a>

```javascript
RawTx = EthereumTxTypeEnvelope || EthereumTransactionType || encode([chainId, nonce, gasTipCap, gasFeeCap, gasLimit, to, value, data, accessList, v, r, s])
```

### Mã hóa RLP (Ví dụ) <a href="#rlp-encoding-example" id="rlp-encoding-example"></a>

Phần dưới đây cho thấy kết quả của quá trình tuần tự hóa RLP và đối tượng giao dịch:

```javascript
    TX(be74e122acf00c2f257e8698ecf01140b58b2880de3f24d0875730425eccb45a)
    Contract: false
    Chaind:   0x2
    From:     a94f5374fce5edbc8e2a8697c15331677e6ebf0b
    To:       7b65b75d204abed71587c9e519a89277766ee1d0
    Nonce:    1234
    GasTipCap: 0x19
    GasFeeCap: 0x19
    GasLimit  0xf4240
    Value:    0xa
    Data:     0x31323334
    AccessList: [{0000000000000000000000000000000000000001 [0000000000000000000000000000000000000000000000000000000000000000]}]
    V:        0x0
    R:        0xca14aa0bada2da7ca1b143c16e2dd4a69f2a1e77ce54c7f6d440fe828a777f4f
    S:        0x117f0f78aed398b2995b5ee7c67ace25d52be3c72c1384c2aaa9683b351556
    Hex:      7802f8a1028204d21919830f4240947b65b75d204abed71587c9e519a89277766ee1d00a8431323334f838f7940000000000000000000000000000000000000001e1a0000000000000000000000000000000000000000000000000000000000000000080a0ca14aa0bada2da7ca1b143c16e2dd4a69f2a1e77ce54c7f6d440fe828a777f4f9f117f0f78aed398b2995b5ee7c67ace25d52be3c72c1384c2aaa9683b351556
```

### Kết quả đầu ra RPC (Example) <a href="#rpc-output-example" id="rpc-output-example"></a>

Phần dưới đây cho thấy một đối tượng giao dịch được trả về qua JSON RPC.

Kết quả trả về của `eth_getTransactionByHash`

```javascript
{
  "blockHash": "0x55792fe186e3d1515fe35a68c2c8d7977b2d7db184d80526f906c53222b77833",
  "blockNumber": "0x1c944d",
  "from": "0x5618e15ec2916bbe6cf2cce20ce31e61d6062cac",
  "gas": "0x174876e800",
  "gasPrice": "0x5d21dba00",
  "maxFeePerGas": "0x5d21dba00",
  "maxPriorityFeePerGas": "0x5d21dba00",
  "hash": "0x5db239963029ad9ef6c3331b10ae455638316e330b0efdae2cc1f8e86884e66e",
  "input": "0x1122",
  "nonce": "0x13",
  "to": "0xa0f1633f4c666d7fe5ba912bd5caf03d3655ac31",
  "transactionIndex": "0x0",
  "value": "0x186a0",
  "type": "0x2",
  "accessList": [
      {
          "address": "0x0000000000000000000000000000000000000001",
          "storageKeys": [
              "0x0000000000000000000000000000000000000000000000000000000000000000"
          ]
      }
  ],
  "chainId": "0x2710",
  "v": "0x1",
  "r": "0x27e007cbe79fd8cc9b89dd798bdd5aa62d038273bf006c7c3b40e13a938ab807",
  "s": "0x6209bb328855f02fa2671fecb41efd9f191b03ecab5e580227fa2a0674879384"
}
```

Kết quả trả về của `klay_getTransactionByHash`

```javascript
{
  "accessList": [
      {
          "address": "0x0000000000000000000000000000000000000001",
          "storageKeys": [
              "0x0000000000000000000000000000000000000000000000000000000000000000"
          ]
      }
  ],
  "blockHash": "0x55792fe186e3d1515fe35a68c2c8d7977b2d7db184d80526f906c53222b77833",
  "blockNumber": "0x1c944d",
  "chainId": "0x2710",
  "from": "0x5618e15ec2916bbe6cf2cce20ce31e61d6062cac",
  "gas": "0x174876e800",
  "hash": "0x5db239963029ad9ef6c3331b10ae455638316e330b0efdae2cc1f8e86884e66e",
  "input": "0x1122",
  "maxFeePerGas": "0x5d21dba00",
  "maxPriorityFeePerGas": "0x5d21dba00",
  "nonce": "0x13",
  "senderTxHash": "0x5db239963029ad9ef6c3331b10ae455638316e330b0efdae2cc1f8e86884e66e",
  "signatures": [
      {
          "V": "0x1",
          "R": "0x27e007cbe79fd8cc9b89dd798bdd5aa62d038273bf006c7c3b40e13a938ab807",
          "S": "0x6209bb328855f02fa2671fecb41efd9f191b03ecab5e580227fa2a0674879384"
      }
  ],
  "to": "0xa0f1633f4c666d7fe5ba912bd5caf03d3655ac31",
  "transactionIndex": "0x0",
  "type": "TxTypeEthereumDynamicFee",
  "typeInt": 30722,
  "value": "0x186a0"
}
```


# Tính toán


# Hợp đồng thông mình Klaytn

Hợp đồng thông minh trong Klaytn là các chương trình triển khai logic nghiệp vụ, trò chơi, thư viện, chuyển nhượng token hoặc bất kỳ loại mã nào tương tác với chuỗi khối Klaytn. Khi các điều kiện được mô tả trong hợp đồng thông minh được thỏa mãn, hợp đồng sẽ thực thi ngay lập tức. Các điều khoản trong hợp đồng thông minh được mô tả bằng ngôn ngữ lập trình; dữ liệu nội dung của chúng được lưu trữ dưới dạng trạng thái của hợp đồng.

Klaytn cung cấp một số phương pháp để soạn và thực thi hợp đồng thông minh trên mạng lưới Klaytn. Đầu tiên, Klaytn hỗ trợ Solidity và duy trì khả năng tương thích với các bộ công cụ phát triển Ethereum, chẳng hạn như Remix hoặc Truffle. Các hợp đồng thông minh viết bằng Solidity có thể được lập bằng các trình biên dịch Solidity sẵn có và thực thi trên Klaytn mà không cần tốn thêm công sức. Vì Solidity là ngôn ngữ lập trình hợp đồng tiêu chuẩn thực tế trong Ethereum và được hỗ trợ bởi những cộng đồng năng động, Klaytn hỗ trợ ngôn ngữ này để cung cấp cho các nhà phát triển một môi trường phát triển quen thuộc nhất, trên đó, các nhà phát triển DApp Ethereum có thể dễ dàng chuyển công việc đã có sang môi trường này.

Trong tương lai, Klaytn dự định sẽ hỗ trợ cho các hợp đồng thông minh được viết bằng nhiều ngôn ngữ lập trình khác, nhằm mở rộng sự hỗ trợ cho phạm vi các nhà phát triển rộng hơn, đồng thời cung cấp cho họ trải nghiệm phát triển mà họ có cảm giác quen thuộc nhất. Trong tương lai, Klaytn sẽ tiếp tục khám phá nhiều ngôn ngữ lập trình đa dạng mà các nhà phát triển có hứng thú.

## Chi phí thực thi hợp đồng thông minh hợp lý <a href="#affordable-smart-contract-execution-cost" id="affordable-smart-contract-execution-cost"></a>

Một trong những lý do khiến chuỗi khối tính phí cho việc thực thi hợp đồng thông minh là để tận dụng các nguồn tài nguyên hữu hạn sao cho hiệu quả bằng cách ngăn chặn vận hành cách hợp đồng được viết sơ sài hoặc độc hại. Điều này có nghĩa là một nền tảng chuỗi khối sẽ tăng chi phí vận hành hợp đồng thông minh một cách có chủ ý (1) để khuyến khích các nhà phát triển viết mã hiệu quả, và (2) để ngăn chặn đối thủ tấn xông bằng cách cắt giảm tối đa lợi ích tài chính dự kiến. Với một chiến lược thành công, số phí được tính trên các lượt thực thi bình thường sẽ ở mức thấp, tuy nhiên, phí từ các lượt thực thi độc hại sẽ ở mức cao. Dù mô hình phí dựa trên mã vận hành của Ethereum rất hữu ích trong việc ngăn chặn sự lãng phí tài nguyên, mô hình này cũng có thể gây trở ngại cho việc thực thi hợp đồng thông minh bình thường do giá gas cao đối với một số mã vận hành (ví dụ như viết trạng thái), cản trở việc áp dụng các công nghệ chuỗi khối. Để xử lý vấn đề này, Klaytn dự định sử dụng mô hình phí cố định dựa trên mã vận hành với đơn giá thấp cho mỗi mã vận hành. Việc này có thể thực hiện được bằng cách gia tăng đáng kể khả năng mở rộng của giao thức chuỗi khối.

Mã vận hành trực tiếp liên quan đến lượng tài nguyên mà nền tảng có thể sử dụng. Chi phí viết trạng thái của Ethereum cao là do có giới hạn về lưu trữ cũng như băng thông cần có của mạng lưới để ghi lại và truyền đi các trạng thái đã thay đổi. Ngược lại, nếu một chuỗi khối có tài nguyên dồi dào (ví dụ như thời gian CPU, lưu trữ, băng thông mạng lưới) thì đơn giá cho mỗi mã vận hành có thể thấp hơn đáng kể so với Ethereum, ngoài ra, sự chênh lệch chi phí giữa các mã vận hành cũng có thể thu hẹp tối đa. Klaytn hướng đến việc cắt giảm đơn giá cho mã vận hành bằng cách chia tỷ lệ từng nút CN theo chiều dọc (nghĩa là mua phần cứng cao cấp), tính toán song song (nghĩa là chia tỷ lệ logic thông qua chuỗi dịch vụ), và chia tỷ lệ các cụm vật lý theo chiều ngang.


# Mô hình thực thi

Trang này mô tả mô hình thực thi, cấu trúc dữ liệu và vòng đời của hợp đồng thông minh Klaytn.

## Mô hình thực thi <a href="#execution-model" id="execution-model"></a>

Giao dịch có thể được tạo ra bởi các API của nền tảng như được mô tả trong [Chi tiết về API của nền tảng](/content/dapp/json-rpc/api-references). Các giao dịch này được gửi đến *Consensus Nodes (CN)* để được lưu trữ trong một khối. Các CN kiểm tra xem từng giao dịch nhận được có hợp lệ không. Các giao dịch hợp lệ được lưu trữ trong bể giao dịch; nếu không hợp lệ, chúng sẽ bị loại bỏ. Một CN chọn các giao dịch có thể thực thi được trong khối hiện tại thuộc bể giao dịch của nó, sau đó, thực thi từng giao dịch một.

Để thực thi một giao dịch, người gửi phải trả một khoản KLAY dưới dạng phí giao dịch. Phí giao dịch tính bằng KLAY này được tính toán dựa trên gas và hệ số nhân, *nghĩa là* đơn giá. Gas là đơn vị tính toán cơ bản. Mỗi hoạt động được thực thi trên một nút Klaytn tiêu thụ một lượng gas được xác định trước. Lượng KLAY chính xác cần dùng cho giao dịch được tính toán theo công thức được minh họa trong [Phí giao dịch](/content/klaytn/design/transaction-fees). Giao dịch có thể thất bại nếu người gửi gửi đi một giao dịch mà không kèm theo đủ gas. Một giao dịch cũng có thể thất bại nếu tài khoản của người gửi không có đủ số dư.

Khi một giao dịch được thực thi thành công, nó sẽ được đưa vào khối hiện tại. Một CN thu thập các giao dịch cho đến khi nó đạt đến giới hạn gas cho một khối hoặc giới hạn thời gian thực hiện một khối. Sau đó, CN sẽ tạo ra một khối với các giao dịch này. Bước này bắt buộc phải điền một số trường trong khối. Ví dụ: nó phải tính toán các giá trị hàm băm của giao dịch, biên lai, trạng thái, v.v. Sau khi tất cả các trường bắt buộc đã được hoàn tất, CN tạo ra một hàm băm của khối.

Khi quá trình tạo khối đã hoàn tất, khối sẽ được truyền đến tất cả các CN khác. Tất cả các CN khác đều xác minh khối được truyền và đạt đến sự đồng thuận về kết quả xác minh bằng cách dùng thuật toán đồng thuận BFT. Khi quá trình xác minh hoàn tất thành công bởi phần lớn các CN, khối này sẽ được lưu trữ trong chuỗi khối. Vì thuật toán đồng thuận BFT thỏa mãn thuộc tính hoàn thiện tức thời, khối này là khối được chốt và sẽ không bao giờ bị loại bỏ. Sau khi một khối đã được hoàn thiện, việc thực thi tất cả các giao dịch trong khối đó sẽ được đảm bảo không thể hoàn tác và kết quả thực thi có thể được trả về người gửi nếu có yêu cầu.

### Các hạn chế đối với việc thực thi giao dịch <a href="#restrictions-on-transaction-execution" id="restrictions-on-transaction-execution"></a>

Các mạng lưới Baobab và Cypress của Klaytn hiện có các hạn chế sau đối với việc thực thi giao dịch:

* Một giao dịch phải đặt giá gas theo [đơn giá](/content/klaytn/design/klaytn-native-coin-klay#units-of-klay) của Klaytn, *nghĩa là* 250 ston.
* Một giao dịch có chi phí thực thi lớn hơn giới hạn chi phí tính toán sẽ bị loại bỏ. Vui lòng tham khảo [chi phí tính toán](/content/klaytn/design/computation/computation-cost)

## Cấu trúc dữ liệu <a href="#data-structures" id="data-structures"></a>

### Tài khoản <a href="#account" id="account"></a>

Tài khoản trong nền tảng chuỗi khối Klaytn là một cấu trúc dữ liệu chứa thông tin về số dư của một người hoặc một hợp đồng thông minh. Klaytn tái thiết kế mô hình tài khoản của mình để cung cấp DX và UX tốt hơn. Bạn có thể tìm thấy thông tin chi tiết về mô hình tài khoản \[tại đây]\(../tài khoảns.md).

### Giao dịch <a href="#transaction" id="transaction"></a>

Một giao dịch trong nền tảng chuỗi khối là một thông điệp mà các nút gửi cho nhau, làm thay đổi trạng thái của chuỗi khối. Klaytn cũng tái thiết kế mô hình giao dịch. Các giao dịch được phân tách thành nhiều loại khác nhau tùy theo mục đích riêng của chúng để tìm ra các cơ hội tối ưu hóa hiệu suất và nhằm hỗ trợ mô hình tài khoản đã được tái thiết kế. Bạn có thể tìm thấy thông tin chi tiết về mô hình giao dịch [tại đây](/content/klaytn/design/transactions).

### Trạng thái <a href="#state" id="state"></a>

**Trạng thái** của Klaytn là một tập hợp các trạng thái của tài khoản. Trạng thái của các nút trên Klaytn phải giống nhau nếu chúng đã xử lý các khối giống nhau theo cùng thứ tự. Trạng thái thay đổi khi một giao dịch được thực thi trên một nút Klaytn.

Bảng dưới đây cho thấy dữ liệu tài khoản được lưu trữ trong trạng thái.

| Thành phần  | Mô tả                                                                                                                                                                                              |
| ----------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| nonce       | Một giá trị số nguyên cho biết số lượng giao dịch được thực thi bởi tài khoản này. Khi gửi đi một giao dịch, số dùng một lần của giao dịch phải bằng số dùng một lần của tài khoản.                |
| số dư       | Một giá trị số nguyên cho thấy lượng KLAY mà tài khoản này đang có.                                                                                                                                |
| storageRoot | Hàm băm 256 bit của gốc của Merkle Patricia Trie có chứa các giá trị của tất cả các biến về lưu trữ trong tài khoản.                                                                               |
| codeHash    | Hàm băm của bytecode của tài khoản. Giá trị này là bất biến, nghĩa là nó chỉ được đặt khi hợp đồng thông minh được tạo. Nếu tài khoản là một EOA hoặc EA, giá trị này được đặt thành hàm băm null. |

### Khối <a href="#block" id="block"></a>

Khối là một yếu tố quan trọng của chuỗi khối Klaytn vì theo đúng nghĩa đen, chuỗi khối được tạo thành bởi một chuỗi gồm nhiều khối. Bảng dưới đây cho thấy các thành phần của một khối.

| Thành phần       | Mô tả                                                                                                                   |
| ---------------- | ----------------------------------------------------------------------------------------------------------------------- |
| baseFeePerGas    | Phí cơ bản trên mỗi đơn vị gas. Giá trị này chỉ được trả về khi EthTxTypeCompatibleBlock được kích hoạt cho số khối đó. |
| blockScore       | Độ khó trước đây. Giá trị luôn là 1 trong công cụ đồng thuận BFT                                                        |
| extraData        | Trường "dữ liệu bổ sung" của khối này.                                                                                  |
| gasUsed          | Tổng số gas đã được sử dụng bởi tất cả các giao dịch trong khối này.                                                    |
| governanceData   | Cấu hình quản trị được mã hóa RLP                                                                                       |
| nhật kýBloom     | Bộ lọc Bloom cho các bản ghi của khối. `null` khi đó là khối đang chờ xử lý.                                            |
| number           | Số khối. `null` khi đó là khối đang chờ xử lý.                                                                          |
| parentHash       | Hàm băm của khối cha của một khối.                                                                                      |
| người đề xuất    | Địa chỉ của người đề xuất khối.                                                                                         |
| receiptsRoot     | Gốc của trie biên lai giao dịch của khối.                                                                               |
| phần thưởng      | Địa chỉ nhận phần thưởng khối.                                                                                          |
| size             | Giá trị nguyên chỉ kích thước của khối này theo byte.                                                                   |
| stateRoot        | Gốc của trie trạng thái cuối của khối.                                                                                  |
| totalBlockScore  | Tổng số blockScore bằng giá trị nguyên của chuỗi cho đến khối này.                                                      |
| transactionsRoot | Gốc của trie giao dịch trong khối.                                                                                      |
| dấu thời gian    | Dấu thời gian Unix khi khối được đối chiếu.                                                                             |
| timestampFoS     | Phần giây của dấu thời gian khi khối được đối chiếu.                                                                    |
| giao dịch        | Mảng đối tượng giao dịch hoặc hàm băm giao dịch 32 byte tùy thuộc vào tham số đã cho gần nhất.                          |
| voteData         | Phiếu bầu quản trị được mã hóa RLP của người đề xuất                                                                    |

## Hợp đồng thông minh <a href="#smart-contract" id="smart-contract"></a>

Một *hợp đồng thông minh* bao gồm một tập hợp các mã (hàm) và dữ liệu (trạng thái) nằm tại một địa chỉ cụ thể trên chuỗi khối Klaytn. Các tài khoản hợp đồng có thể truyền thông điệp cho nhau cũng như thực hiện tính toán tương đương với Turing Complete. Các hợp đồng tồn tại trên chuỗi khối dưới định dạng nhị phân của riêng Klaytn. Hiện tại, Klaytn hỗ trợ một định dạng nhị phân --bytecode của Máy ảo Ethereum (EVM); tuy nhiên, các định dạng khác cũng sẽ được hỗ trợ trong tương lai.

### Tạo hợp đồng thông minh <a href="#creating-smart-contracts" id="creating-smart-contracts"></a>

Một hợp đồng thông minh có thể được tạo ra trong chuỗi khối Klaytn bằng cách gửi một giao dịch đến một địa chỉ trống với dữ liệu ở dạng nhị phân. Dữ liệu nhị phân có thể có nhiều định dạng; tuy nhiên, hiện tại Klaytn hỗ trợ một định dạng nhị phân là bytecode EVM. Bạn cần lưu ý rằng giao dịch này bắt buộc phải trả phí thực thi. Số dư tài khoản của tài khoản người gửi sẽ bị khấu trừ dựa trên mô hình phí giao dịch sau khi giao dịch được lưu trữ vào một khối. Sau một thời gian, giao dịch sẽ xuất hiện trong một khối, điều này xác nhận rằng trạng thái mà nó cần có đã đạt được sự đồng thuận. Tại thời điểm này, hợp đồng thông minh đã tồn tại trong chuỗi khối Klaytn. As [eip-3541](https://eips.ethereum.org/EIPS/eip-3541) is brought at the Kore hardfork, deployment of a new code starting with the 0xEF byte is not allowed.

### Thực thi hợp đồng thông minh <a href="#executing-smart-contracts" id="executing-smart-contracts"></a>

Hàm của một hợp đồng thông minh có thể được gọi và thực thi bằng cách gửi một giao dịch đến hợp đồng thông minh hoặc bằng cách gọi hàm trong nút theo cách cục bộ. Khi một hàm được gọi theo cách gửi một giao dịch, hàm này sẽ được thực thi bằng cách xử lý một giao dịch. Cách này cần có chi phí tính bằng KLAY để gửi giao dịch, và cuộc gọi sẽ được ghi lại vĩnh viễn trên chuỗi khối. Giá trị trả về của các cuộc gọi được thực hiện theo cách này chính là hàm băm của giao dịch. Khi hàm được gọi cục bộ, nó sẽ được thực thi cục bộ trong Máy ảo Klaytn (KLVM) và cuộc gọi này sẽ trả về giá trị trả về của hàm. Các cuộc gọi được thực hiện theo cách này sẽ không được ghi lại trên chuỗi khối; vì thế, chúng không thể thay đổi trạng thái nội bộ của hợp đồng. Loại cuộc gọi này được đặt tên là cuộc gọi hàm hằng. Các cuộc gọi được thực hiện bằng cách này không tốn KLAY. Các cuộc gọi hàm hằng nên được sử dụng khi mối quan tâm duy nhất là giá trị trả về, tuy nhiên, giao dịch nên được sử dụng khi mối quan tâm là các phản ứng phụ đối với trạng thái của hợp đồng.

### Vô hiệu hóa hợp đồng thông minh <a href="#disabling-smart-contracts" id="disabling-smart-contracts"></a>

Vì hợp đồng thông minh tồn tại trong chuỗi khối Klaytn, chúng không thể bị xóa mà chỉ có thể bị vô hiệu hóa. Hiện tại, Klaytn đã áp dụng quy trình tương tự để vô hiệu hóa hợp đồng thông minh Klaytn, giống cách vô hiệu hóa hợp đồng thông minh trong Ethereum. Ví dụ: hợp đồng thông minh Klaytn cho KLVM có thể bị vô hiệu hóa bằng cách dùng cuộc gọi [`selfdestruct(address recipient)`](https://solidity.readthedocs.io/en/v0.5.6/introduction-to-smart-contracts.html#self-destruct) bằng ngôn ngữ Solidity (hoặc mã vận hành KLVM `SELFDESTRUCT`). Đội ngũ Klaytn cũng sẽ cung cấp các phương pháp để vô hiệu hóa hợp đồng thông minh dành cho các môi trường thực thi khác.

### Nâng cấp hợp đồng thông minh <a href="#upgrading-smart-contracts" id="upgrading-smart-contracts"></a>

Klaytn sẽ cung cấp các phương pháp để nâng cấp một hợp đồng thông minh đã triển khai để giải quyết vấn đề về trải nghiệm bất tiện của người dùng với các chuỗi khối hiện có. Ví dụ: các dịch vụ đã triển khai trên chuỗi khối rất khó nâng cấp. Klaytn sẽ cung cấp các khuôn khổ và thư viện hợp đồng thông minh để cho phép các nhà cung cấp dịch vụ (SP) nâng cấp các dịch vụ đã triển khai và di chuyển thông tin dịch vụ. Klaytn sẽ cung cấp tính năng này với sự cẩn trọng bằng cách xem xét các yêu cầu sau đây.

* Chỉ những tài khoản được cấp phép hoặc người sở hữu hợp đồng thông minh mới có thể nâng cấp hợp đồng thông minh.
* Những hợp đồng thông minh đã được nâng cấp sẽ có thể sửa đổi dữ liệu sẵn có vốn được hợp đồng thông minh cũ lưu giữ.
* Các hợp đồng thông minh khác có liên quan đến những hợp đồng thông minh cũ sẽ có thể quyết định về việc có dùng các phiên bản mới hơn, đã nâng cấp của những hợp đồng thông minh đó hay không.


# Chi phí tính toán

Vì Klaytn hướng đến việc duy trì khoảng thời gian xử lý khối là 1 giây, thời gian thực thi giao dịch cần phải được kiểm soát. Dưới đây là ba hướng tiếp cận để đạt được điều đó:

1. Hạn chế giới hạn gas của một giao dịch
2. Hạn chế thời gian thực thi của một giao dịch
3. Hạn chế chi phí tính toán của một giao dịch

Việc hạn chế giới hạn gas của một giao dịch không phải là một giải pháp khả thi do khái niệm về gas đại diện cho giá trị trao đổi hiện tại của nhiều nguồn tài nguyên khác nhau trên nền tảng chuỗi khối, chẳng hạn như tính toán, lưu trữ, băng thông mạng lưới, v.v. Hướng tiếp cận này không phù hợp để làm chỉ số cho thời gian thực thi giao dịch.

Việc hạn chế thời gian thực thi giao dịch cũng không khả thi vì thời gian thực thi có thể khác nhau giữa các nút trên nền tảng chuỗi khối. Ví dụ: hãy xem xét trường hợp chúng ta hạn chế thời gian thực thi một giao dịch ở mức 100 mili-giây. Nếu một nút thực thi một giao dịch trong 90 mili-giây và một nút khác thực thi trong 110 mili-giây, hai nút này sẽ không thể đạt được sự đồng thuận. Vì thế, giải pháp này không phù hợp.

Hướng tiếp cận cuối cùng là giới hạn chi phí tính toán của một giao dịch. Chúng tôi đã lập mô hình chi phí tính toán của từng mã vận hành EVM dựa trên thời gian thực thi thật và hạn chế tổng chi phí tính toán của một giao dịch. Với hướng tiếp cận này, chúng tôi loại trừ các yếu tố khác, chỉ tính đơn vị thời gian thực thi chuẩn hóa và các nút cũng có thể đạt được sự đồng thuận.ể đạt được sự đồng thuận.

Vì thế, chúng tôi đã chọn phương án thứ ba cho Klaytn. Hiện tại, giới hạn chi phí thực thi được đặt ở mức 100.000.000. Vì giới hạn này là do nền tảng quyết định, các nhà phát triển nên lưu ý đến chi phí tính toán của giao dịch. Để tính chi phí tính toán của một giao dịch, Klaytn cung cấp [klay\_estimateComputationCost](/content/dapp/json-rpc/api-references/klay/transaction#klay_estimatecomputationcost). Cách sử dụng gần giống như [klay\_estimateGas](/content/dapp/json-rpc/api-references/klay/transaction#klay_estimategas).

## Chi phí tính toán của mã vận hành <a href="#computation-cost-of-opcodes" id="computation-cost-of-opcodes"></a>

Bảng dưới đây cho thấy chi phí tính toán của các mã vận hành EVM. Chi phí tính toán được xác định dựa trên các thử nghiệm.

{% hint style="success" %}
LƯU Ý: Chi phí tính toán đã thay đổi cùng với việc nâng cấp giao thức `IstanbulEVM` hay còn gọi là "hard fork". Nếu bạn muốn đọc tài liệu trước đây, vui lòng tham khảo phần [tài liệu trước đây](/content/klaytn/design/computation/computation-cost/computation-cost-previous).

Số khối nâng cấp giao thức `IstanbulEVM` như sau.

* Mạng thử nghiệm Baobab: `#75373312`
* Mạng chính thức Cypress: `#86816005`
  {% endhint %}

| Mã vận hành    | ComputationCost |
| -------------- | --------------: |
| STOP           |               0 |
| ADD            |             150 |
| MUL            |             200 |
| SUB            |             219 |
| DIV            |             404 |
| SDIV           |             739 |
| MOD            |             812 |
| SMOD           |             560 |
| ADDMOD         |            1410 |
| MULMOD         |            1760 |
| EXP            |            5000 |
| SIGNEXTEND     |             481 |
| LT             |             201 |
| GT             |             264 |
| SLT            |             176 |
| SGT            |             222 |
| EQ             |             220 |
| ISZERO         |             165 |
| AND            |             288 |
| OR             |             160 |
| XOR            |             454 |
| NOT            |             364 |
| BYTE           |             589 |
| SHL            |             478 |
| SHR            |             498 |
| SAR            |             834 |
| SHA3           |            2465 |
| ADDRESS        |             284 |
| SỐ DƯ          |            1407 |
| ORIGIN         |             210 |
| CALLER         |             188 |
| CALLVALUE      |             149 |
| CALLDATALOAD   |             596 |
| CALLDATASIZE   |             194 |
| CALLDATACOPY   |             100 |
| CODESIZE       |             145 |
| CODECOPY       |             898 |
| GASPRICE       |             131 |
| EXTCODESIZE    |            1481 |
| EXTCODECOPY    |            1000 |
| RETURNDATASIZE |              10 |
| RETURNDATACOPY |              40 |
| EXTCODEHASH    |            1000 |
| BLOCKHASH      |             500 |
| COINBASE       |             189 |
| TIMESTAMP      |             265 |
| NUMBER         |             202 |
| PREVRANDAO     |            1498 |
| GASLIMIT       |             166 |
| CHAINID        |             120 |
| SELFBALANCE    |             374 |
| POP            |             140 |
| MLOAD          |             376 |
| MSTORE         |             288 |
| MSTORE8        |            5142 |
| SLOAD          |             835 |
| SSTORE         |            1548 |
| JUMP           |             253 |
| JUMPI          |             176 |
| PC             |             147 |
| MSIZE          |             137 |
| GAS            |             230 |
| JUMPDEST       |              10 |
| PUSH0          |              80 |
| PUSH1          |             120 |
| PUSH2          |             120 |
| PUSH3          |             120 |
| PUSH4          |             120 |
| PUSH5          |             120 |
| PUSH6          |             120 |
| PUSH7          |             120 |
| PUSH8          |             120 |
| PUSH9          |             120 |
| PUSH10         |             120 |
| PUSH11         |             120 |
| PUSH12         |             120 |
| PUSH13         |             120 |
| PUSH14         |             120 |
| PUSH15         |             120 |
| PUSH16         |             120 |
| PUSH17         |             120 |
| PUSH18         |             120 |
| PUSH19         |             120 |
| PUSH20         |             120 |
| PUSH21         |             120 |
| PUSH22         |             120 |
| PUSH23         |             120 |
| PUSH24         |             120 |
| PUSH25         |             120 |
| PUSH26         |             120 |
| PUSH27         |             120 |
| PUSH28         |             120 |
| PUSH29         |             120 |
| PUSH30         |             120 |
| PUSH31         |             120 |
| PUSH32         |             120 |
| DUP1           |             190 |
| DUP2           |             190 |
| DUP3           |             176 |
| DUP4           |             142 |
| DUP5           |             177 |
| DUP6           |             165 |
| DUP7           |             147 |
| DUP8           |             157 |
| DUP9           |             138 |
| DUP10          |             174 |
| DUP11          |             141 |
| DUP12          |             144 |
| DUP13          |             157 |
| DUP14          |             143 |
| DUP15          |             237 |
| DUP16          |             149 |
| SWAP1          |             141 |
| SWAP2          |             156 |
| SWAP3          |             145 |
| SWAP4          |             135 |
| SWAP5          |             115 |
| SWAP6          |             146 |
| SWAP7          |             199 |
| SWAP8          |             130 |
| SWAP9          |             160 |
| SWAP10         |             134 |
| SWAP11         |             147 |
| SWAP12         |             128 |
| SWAP13         |             121 |
| SWAP14         |             114 |
| SWAP15         |             197 |
| SWAP16         |             128 |
| LOG0           |             100 |
| LOG1           |            1000 |
| LOG2           |            1000 |
| LOG3           |            1000 |
| LOG4           |            1000 |
| PUSH           |               0 |
| DUP            |               0 |
| SWAP           |               0 |
| CREATE         |            2094 |
| LỆNH GỌI       |            5000 |
| CALLCODE       |            4000 |
| RETURN         |               0 |
| DELEGATECALL   |             696 |
| CREATE2        |           10000 |
| STATICCALL     |           10000 |
| REVERT         |               0 |
| SELFDESTRUCT   |               0 |
| BASEFEE        |             198 |


# Chi phí tính toán (Các tài liệu trước)

Vì Klaytn hướng đến việc duy trì khoảng thời gian xử lý khối là 1 giây, thời gian thực thi giao dịch cần phải được kiểm soát. Dưới đây là ba hướng tiếp cận để đạt được điều đó:

1. Hạn chế giới hạn gas của một giao dịch
2. Hạn chế thời gian thực thi của một giao dịch
3. Hạn chế chi phí tính toán của một giao dịch

Việc hạn chế giới hạn gas của một giao dịch không phải là một giải pháp khả thi do khái niệm về gas đại diện cho giá trị trao đổi hiện tại của nhiều nguồn tài nguyên khác nhau trên nền tảng chuỗi khối, chẳng hạn như tính toán, lưu trữ, băng thông mạng lưới, v.v. Hướng tiếp cận này không phù hợp để làm chỉ số cho thời gian thực thi giao dịch.

Việc hạn chế thời gian thực thi giao dịch cũng không khả thi vì thời gian thực thi có thể khác nhau giữa các nút trên nền tảng chuỗi khối. Ví dụ: hãy xem xét trường hợp chúng ta hạn chế thời gian thực thi một giao dịch ở mức 100 mili-giây. Nếu một nút thực thi một giao dịch trong 90 mili-giây và một nút khác thực thi trong 110 mili-giây, hai nút này sẽ không thể đạt được sự đồng thuận. Vì thế, giải pháp này không phù hợp.

Hướng tiếp cận cuối cùng là giới hạn chi phí tính toán của một giao dịch. Chúng tôi đã lập mô hình chi phí tính toán của từng mã vận hành EVM dựa trên thời gian thực thi thật và hạn chế tổng chi phí tính toán của một giao dịch. Với hướng tiếp cận này, chúng tôi loại trừ các yếu tố khác, chỉ tính đơn vị thời gian thực thi chuẩn hóa và các nút cũng có thể đạt được sự đồng thuận.

Vì thế, chúng tôi đã chọn phương án thứ ba cho Klaytn. Hiện tại, giới hạn chi phí thực thi được đặt ở mức 100.000.000. Vì giới hạn này là do nền tảng quyết định, các nhà phát triển nên lưu ý đến chi phí tính toán của giao dịch. Để tính chi phí tính toán của một giao dịch, Klaytn cung cấp [klay\_estimateComputationCost](/content/dapp/json-rpc/api-references/klay/transaction#klay_estimateComputationCost). Cách sử dụng gần giống như [klay\_estimateGas](/content/dapp/json-rpc/api-references/klay/transaction#klay_estimateGas).

## Chi phí tính toán của mã vận hành <a href="#computation-cost-of-opcodes" id="computation-cost-of-opcodes"></a>

Bảng dưới đây cho thấy chi phí tính toán của các mã vận hành EVM. Chi phí tính toán được xác định dựa trên các thử nghiệm.

{% hint style="success" %}
LƯU Ý: Tài liệu này chứa chi phí tính toán được sử dụng trước thời điểm kích hoạt nâng cấp giao thức. Nếu bạn muốn nhận tài liệu mới nhất, vui lòng tham khảo [tài liệu mới nhất](/content/klaytn/design/computation/computation-cost).
{% endhint %}

| Mã vận hành    | ComputationCost |
| -------------- | --------------: |
| STOP           |               0 |
| ADD            |             150 |
| MUL            |             200 |
| SUB            |             219 |
| DIV            |             404 |
| SDIV           |             739 |
| MOD            |             812 |
| SMOD           |             560 |
| ADDMOD         |            3349 |
| MULMOD         |            4757 |
| EXP            |            5000 |
| SIGNEXTEND     |             481 |
| LT             |             201 |
| GT             |             264 |
| SLT            |             176 |
| SGT            |             222 |
| EQ             |             220 |
| ISZERO         |             165 |
| AND            |             288 |
| OR             |             160 |
| XOR            |             657 |
| NOT            |            1289 |
| BYTE           |             589 |
| SHL            |            1603 |
| SHR            |            1346 |
| SAR            |            1815 |
| SHA3           |            2465 |
| ADDRESS        |             284 |
| SỐ DƯ          |            1407 |
| ORIGIN         |             210 |
| CALLER         |             188 |
| CALLVALUE      |             149 |
| CALLDATALOAD   |             596 |
| CALLDATASIZE   |             194 |
| CALLDATACOPY   |             100 |
| CODESIZE       |             145 |
| CODECOPY       |             898 |
| GASPRICE       |             131 |
| EXTCODESIZE    |            1481 |
| EXTCODECOPY    |            1000 |
| RETURNDATASIZE |              10 |
| RETURNDATACOPY |              40 |
| EXTCODEHASH    |            1000 |
| BLOCKHASH      |             500 |
| COINBASE       |             189 |
| TIMESTAMP      |             265 |
| NUMBER         |             202 |
| DIFFICULTY     |             180 |
| GASLIMIT       |             166 |
| POP            |             140 |
| MLOAD          |             376 |
| MSTORE         |             288 |
| MSTORE8        |            5142 |
| SLOAD          |             835 |
| SSTORE         |            1548 |
| JUMP           |             253 |
| JUMPI          |             176 |
| PC             |             147 |
| MSIZE          |             137 |
| GAS            |             230 |
| JUMPDEST       |              10 |
| PUSH1          |             120 |
| PUSH2          |             120 |
| PUSH3          |             120 |
| PUSH4          |             120 |
| PUSH5          |             120 |
| PUSH6          |             120 |
| PUSH7          |             120 |
| PUSH8          |             120 |
| PUSH9          |             120 |
| PUSH10         |             120 |
| PUSH11         |             120 |
| PUSH12         |             120 |
| PUSH13         |             120 |
| PUSH14         |             120 |
| PUSH15         |             120 |
| PUSH16         |             120 |
| PUSH17         |             120 |
| PUSH18         |             120 |
| PUSH19         |             120 |
| PUSH20         |             120 |
| PUSH21         |             120 |
| PUSH22         |             120 |
| PUSH23         |             120 |
| PUSH24         |             120 |
| PUSH25         |             120 |
| PUSH26         |             120 |
| PUSH27         |             120 |
| PUSH28         |             120 |
| PUSH29         |             120 |
| PUSH30         |             120 |
| PUSH31         |             120 |
| PUSH32         |             120 |
| DUP1           |             190 |
| DUP2           |             190 |
| DUP3           |             176 |
| DUP4           |             142 |
| DUP5           |             177 |
| DUP6           |             165 |
| DUP7           |             147 |
| DUP8           |             157 |
| DUP9           |             138 |
| DUP10          |             174 |
| DUP11          |             141 |
| DUP12          |             144 |
| DUP13          |             157 |
| DUP14          |             143 |
| DUP15          |             237 |
| DUP16          |             149 |
| SWAP1          |             141 |
| SWAP2          |             156 |
| SWAP3          |             145 |
| SWAP4          |             135 |
| SWAP5          |             115 |
| SWAP6          |             146 |
| SWAP7          |             199 |
| SWAP8          |             130 |
| SWAP9          |             160 |
| SWAP10         |             134 |
| SWAP11         |             147 |
| SWAP12         |             128 |
| SWAP13         |             121 |
| SWAP14         |             114 |
| SWAP15         |             197 |
| SWAP16         |             128 |
| LOG0           |             100 |
| LOG1           |            1000 |
| LOG2           |            1000 |
| LOG3           |            1000 |
| LOG4           |            1000 |
| PUSH           |               0 |
| DUP            |               0 |
| SWAP           |               0 |
| CREATE         |            2094 |
| LỆNH GỌI       |            5000 |
| CALLCODE       |            4000 |
| RETURN         |               0 |
| DELEGATECALL   |             696 |
| CREATE2        |           10000 |
| STATICCALL     |           10000 |
| REVERT         |               0 |
| SELFDESTRUCT   |               0 |


# Máy ảo Klaytn

{% hint style="success" %}
NOTE: KLVM has changed with the `Kore` hardfork. If you want the previous document, please refer to [previous document](/content/klaytn/design/computation/klaytn-virtual-machine/klaytn-virtual-machine-previous).

`Kore` hardfork block numbers are as follows.

* Baobab Testnet: `#111736800`
* Cypress Mainnet: `#119750400`
  {% endhint %}

## Tổng quan <a href="#overview" id="overview"></a>

Phiên bản hiện tại của Máy ảo Klaytn (KLVM) có nguồn gốc từ Máy ảo Ethereum (EVM). Nội dung của chương này chủ yếu dựa theo [Ethereum Yellow Paper](https://github.com/ethereum/yellowpaper). KLVM liên tục được cải thiện bởi đội ngũ Klaytn, vì thế, tài liệu này có thể được cập nhật thường xuyên. Vui lòng không coi tài liệu này là phiên bản cuối cùng về thông số kỹ thuật của KLVM. Như đã được mô tả trong tuyên bố lập trường, đội ngũ Klaytn cũng có dự định áp dụng các máy ảo khác hoặc môi trường thực thi khác nhằm củng cố khả năng và hiệu suất của nền tảng Klaytn. Chương này đề cập đến thông số kỹ thuật của KLVM và sự khác biệt giữa KLVM và EVM.

KLVM là một cỗ máy trạng thái ảo, chính thức chỉ định mô hình thực thi của Klaytn. Mô hình thực thi này chỉ định cách thay đổi trạng thái hệ thống dựa trên một loạt chỉ thị bytecode và một tuple dữ liệu môi trường nhỏ. KLVM là một cỗ máy gần giống với Turing Complete, tính chất *gần giống* này bắt nguồn từ một thực tế là việc tính toán chịu sự ràng buộc nội tại qua một tham số, *gas*, tham số này hạn chế tổng lượng tính toán được thực hiện.

KLVM thực thi mã máy ảo Klaytn (hoặc bytecode Klaytn), trong đó có chứa một chuỗi các hướng dẫn KLVM. Mã KLVM là ngôn ngữ lập trình được dùng cho các tài khoản trên chuỗi khối Klaytn có chứa mã. Mã KLVM liên kết với một tài khoản được thực thi mỗi lần có một tin nhắn được gửi đến tài khoản đó; mã này có khả năng đọc/viết dữ liệu từ/vào lưu trữ và gửi tin nhắn.

## Thông số kỹ thuật của KLVM <a href="#klvm-specification" id="klvm-specification"></a>

### Các quy tắc <a href="#conventions" id="conventions"></a>

Trong tài liệu này, chúng tôi sử dụng các ký hiệu và quy tắc sau.

* `A := B`
  * `:=` được dùng để xác định `A` là `B`.
* Chúng tôi sử dụng thuật ngữ "hợp đồng thông minh" và "hợp đồng" thay thế lẫn nhau.

### Ký hiệu <a href="#symbols" id="symbols"></a>

Bảng dưới đây tóm tắt các ký hiệu được dùng trong thông số kỹ thuật của KLVM.

#### Các ký hiệu liên quan đến chuỗi khối <a href="#blockchain-related-symbols" id="blockchain-related-symbols"></a>

| Ký hiệu    | Mô tả                          |
| ---------- | ------------------------------ |
| `BC`       | Chuỗi khối                     |
| `B`        | Khối                           |
| `B_header` | Tiêu đề khối của khối hiện tại |

#### Các ký hiệu liên quan đến trạng thái <a href="#state-related-symbols" id="state-related-symbols"></a>

| Ký hiệu          | Mô tả                                         |
| ---------------- | --------------------------------------------- |
| `S`              | Trạng thái                                    |
| `S_system`       | Trạng thái của hệ thống                       |
| `S_machine`      | Trạng thái của máy                            |
| `P_modify_state` | Quyền được phép thực hiện thay đổi trạng thái |

#### Các ký hiệu liên quan đến giao dịch <a href="#transaction-related-symbols" id="transaction-related-symbols"></a>

| Ký hiệu   | Mô tả                                                                                                                                                              |
| --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `T`       | Giao dịch                                                                                                                                                          |
| `T_code`  | Một mảng byte chứa mã máy cần thực thi                                                                                                                             |
| `T_data`  | Một mảng byte chứa dữ liệu đầu vào để thực thi; nếu tác nhân thực thi là một giao dịch, dữ liệu này sẽ là dữ liệu giao dịch.                                       |
| `T_value` | Một giá trị tình bằng peb được đưa vào tài khoản như một phần của quy trình thực thi; nếu tác nhân thực thi là một giao dịch, giá trị này sẽ là giá trị giao dịch. |
| `T_depth` | Độ sâu của ngăn xếp dữ liệu tin nhắn-cuộc gọi hoặc tạo hợp đồng (*nghĩa là* số lượng `CALL` hoặc `CREATE` đang được thực thi ở thời điểm hiện tại)                 |

#### Các ký hiệu liên quan đến gas <a href="#gas-related-symbols" id="gas-related-symbols"></a>

| Ký hiệu   | Mô tả                                              |
| --------- | -------------------------------------------------- |
| `G`       | Gas                                                |
| `G_rem`   | Lượng gas còn lại để tính toán                     |
| `G_price` | Giá gas trong giao dịch phát sinh từ việc thực thi |

#### Các ký hiệu liên quan đến địa chỉ <a href="#address-related-symbols" id="address-related-symbols"></a>

| Ký hiệu           | Mô tả                                                                                                                              |
| ----------------- | ---------------------------------------------------------------------------------------------------------------------------------- |
| `A`               | Địa chỉ                                                                                                                            |
| `A_code_owner`    | Địa chỉ của tài khoản sở hữu mã thực thi                                                                                           |
| `A_tx_sender`     | Địa chỉ người gửi của giao dịch phát sinh từ việc thực thi hiện tại                                                                |
| `A_code_executor` | địa chỉ của tài khoản bắt đầu việc thực thi mã; nếu tác nhân thực thi là một giao dịch, địa chỉ này sẽ là của người gửi giao dịch. |

#### Hàm <a href="#functions" id="functions"></a>

|  Ký hiệu  | Mô tả                                                                                                                           |
| :-------: | ------------------------------------------------------------------------------------------------------------------------------- |
| `F_apply` | Một hàm áp dụng một giao dịch kèm dữ liệu đầu vào cho một trạng thái cho trước và trả về trạng thái tổng hợp kèm dữ liệu đầu ra |

### Cơ bản <a href="#basics" id="basics"></a>

KLVM là một kiến trúc dựa trên ngăn xếp dữ liệu đơn giản. Kích thước từ của máy (cũng là kích thước của các mục trong ngăn xếp dữ liệu) là 256 bit. Con số này được chọn để tạo điều kiện thuận lợi cho hệ thống hàm băm Keccak-256 và các tính toán đường cong elip. Mô hình bộ nhớ là một mảng byte chứa từ có gắn địa chỉ đơn giản. Ngăn xếp dữ liệu có kích thước tối đa là 1024. Máy cũng có một mô hình lưu trữ độc lập; về khái niệm thì nó cũng giống như bộ nhớ, nhưng thay vì một mảng byte, nó là một mảng từ với khả năng xác định địa chỉ từ. Khác với bộ nhớ mang tính biến động, lưu trữ không biến động và được duy trì như một phần của trạng thái hệ thống. Tất cả các vị trí trong lưu trữ và bộ nhớ đều được xác định bằng 0 ngay từ đầu.

Máy không tuân theo kiến trúc von Neumann tiêu chuẩn. Thay vì lưu trữ mã chương trình trong một bộ nhớ hoặc lưu trữ dễ truy cập, mã được lữu trữ riêng trong một bộ nhớ ảo chỉ đọc và chỉ có thể được tương tác qua các chỉ thị chuyên biệt.

Máy có thể thực thi mã ngoại lệ vì một số lí do, bao gồm hiện tượng tràn dưới ngăn xếp và chỉ thị không hợp lệ. Tương tự như trường hợp ngoại lệ hết gas, những ngoại lệ này không giữ nguyên các thay đổi về trạng thái. Thay vào đó, máy ảo sẽ tạm dừng ngay lập tức và báo cáo vấn đề cho tác nhân thực thi (trình xử lý giao dịch hoặc theo cách đệ quy, môi trường thực thi phát sinh), việc này sẽ được xử lý riêng biệt.

### Tổng quan về phí <a href="#fees-overview" id="fees-overview"></a>

Phí (được ghi bằng gas) được tính trong ba trường hợp riêng biệt, cả ba trường hợp đều là điều kiện tiên quyết để thực thi hoạt động. Trường hợp đầu tiên và phổ biến nhất là phí nội tại để tính toán hoạt động. Trường hợp thứ hai, gas có thể được trừ để hình thành một khoản thanh toán cho một cuộc gọi tin nhắn phụ thuộc hoặc tạo hợp đồng; đây là một phần trong khoản thanh toán dành cho `CREATE`, `CALL` và `CALLCODE`. Cuối cùng, gas có thể được tính do có sự tăng lên trong việc sử dụng bộ nhớ.

Trong quá trình thực thi tài khoản, tổng phí phải trả cho việc sử dụng bộ nhớ phải trả tỷ lệ thuận với bội số nhỏ nhất của 32 byte cần có để bao gồm tất cả các chỉ báo bộ nhớ (dù là để đọc hay để ghi) trong phạm vi. Phí này được thanh toán dựa trên cơ sở kịp thời; do đó, việc tham chiếu một vùng bộ nhớ có kích thước lớn hơn ít nhất 32 byte so với bất kỳ bộ nhớ nào khác được lập chỉ mục trước đó sẽ dẫn đến phí sử dụng bộ nhớ bổ sung. Do phí này, các địa chỉ ít có khả năng vượt quá giới hạn 32 bit. Như vậy nghĩa là việc triển khai phải có khả năng kiểm soát được tình huống này.

Phí lưu trữ có cách vận hành hơi khác biệt. Để khuyến khích việc giảm thiểu sử dụng bộ nhớ (tương ứng trực tiếp với một cơ sở dữ liệu trạng thái lớn hơn trên tất cả các nút), phí thực thi cho một hoạt động xóa mục nhập khỏi lưu trữ sẽ được miễn phí và đủ điều kiện để nhận hoàn phí; trên thực tế, khoản hoàn phí này được thanh toán trước vì chi phí sử dụng ban đầu của một vị trí lưu trữ lại cao hơn đáng kể so với việc sử dụng thông thường.

#### Biểu phí <a href="#fee-schedule" id="fee-schedule"></a>

Biểu phí `G` là một tuple gồm 37 giá trị vô hướng, tương ứng với chi phí tương đối tính bằng gas của một số hoạt động trừu tượng mà một giao dịch có thể làm phát sinh. Để xem các bảng khác như `Precompiled contracts` và `tài khoảns`, vui lòng tham khảo [tài liệu này](/content/klaytn/design/transaction-fees#klaytns-gas-table)

{% hint style="success" %}
LƯU Ý: Phí đã thay đổi sau việc nâng cấp giao thức `IstanbulEVM` hay còn gọi là "hard fork". Nếu bạn muốn đọc tài liệu trước đây, vui lòng tham khảo phần [tài liệu trước đây](/content/klaytn/design/computation/klaytn-virtual-machine/klaytn-virtual-machine-previous).

Số khối nâng cấp giao thức `IstanbulEVM` như sau.

* Mạng thử nghiệm Baobab: `#75373312`
* Mạng chính thức Cypress: `#86816005`
  {% endhint %}

| Tên               | Giá trị | Mô tả                                                                                                                  |
| ----------------- | ------: | ---------------------------------------------------------------------------------------------------------------------- |
| `G_zero`          |       0 | Không cần thanh toán cho các hoạt động của bộ `W_zero`                                                                 |
| `G_base`          |       2 | Lượng gas thanh toán cho các hoạt động của bộ `W_base`                                                                 |
| `G_verylow`       |       3 | Lượng gas thanh toán cho các hoạt động của bộ `W_verylow`                                                              |
| `G_low`           |       5 | Lượng gas thanh toán cho các hoạt động của bộ `W_low`                                                                  |
| `G_mid`           |       8 | Lượng gas thanh toán cho các hoạt động của bộ `W_mid`                                                                  |
| `G_high`          |      10 | Lượng gas thanh toán cho các hoạt động của bộ `W_high`                                                                 |
| `G_blockhash`     |      20 | Khoản thanh toán cho một hoạt động `BLOCKHASH`                                                                         |
| `G_extcode`       |     700 | Lượng gas thanh toán cho các hoạt động của bộ `W_extcode`                                                              |
| `G_balance`       |     700 | Lượng gas thanh toán cho một hoạt động `BALANCE`                                                                       |
| `G_sload`         |     800 | Lượng gas thanh toán cho một hoạt động `SLOAD`                                                                         |
| `G_jumpdest`      |       1 | Lượng gas thanh toán cho một hoạt động `JUMPDEST`                                                                      |
| `G_sset`          |   20000 | Lượng gas thanh toán cho một hoạt động `SSTORE` khi giá trị lưu trữ được đặt từ số khác 0 sang số 0                    |
| `G_sreset`        |    5000 | Lượng gas thanh toán cho một hoạt động `SSTORE` khi giá trị lưu trữ giữ nguyên không đổi ở mức 0 hoặc được đặt thành 0 |
| `R_sclear`        |   15000 | Khoản hoàn tiền đã được thực hiện (được thêm vào bộ đếm hoàn tiền) khi giá trị lưu trữ được đặt từ số khác 0 sang số 0 |
| `R_selfdestruct`  |   24000 | Khoản hoàn tiền đã thực hiện (được thêm vào bộ đếm hoàn tiền) cho việc tự hủy một tài khoản                            |
| `G_selfdestruct`  |    5000 | Lượng gas thanh toán cho một hoạt động `SELFDESTRUCT`                                                                  |
| `G_create`        |   32000 | Lượng gas thanh toán cho một hoạt động `CREATE`                                                                        |
| `G_codedeposit`   |     200 | Lượng gas thanh toán cho mỗi byte cho một hoạt động `CREATE` thành công trong việc đặt mã vào trạng thái               |
| `G_call`          |     700 | Lượng gas thanh toán cho một hoạt động `CALL`                                                                          |
| `G_callvalue`     |    9000 | Lượng gas thanh toán một giao dịch chuyển giá trị khác 0 như một phần của hoạt động `CALL`                             |
| `G_callstipend`   |    2300 | Khoản trợ cấp cho hợp đồng được gọi ra, được trừ khỏi `G_callvalue` đối với giao dịch chuyển giá trị khác 0            |
| `G_newtài khoản`  |   25000 | Lượng gas thanh toán cho một hoạt động `CALL` hoặc `SELFDESTRUCT` tạo ra một tài khoản                                 |
| `G_exp`           |      10 | Khoản thanh toán một phần cho một hoạt động `EXP`                                                                      |
| `G_expbyte`       |      50 | Khoản thanh toán một phần khi nhân với `ceil(log_256(exponent))` cho một hoạt động `EXP`                               |
| `G_memory`        |       3 | Lượng gas thanh toán cho mỗi một từ bổ sung khi mở rộng bộ nhớ                                                         |
| `G_txcreate`      |   32000 | Lượng gas được trả bởi tất cả các giao dịch tạo hợp đồng                                                               |
| `G_txdatazero`    |       4 | Lượng gas thanh toán cho mỗi byte 0 của dữ liệu hoặc mã cho một giao dịch                                              |
| `G_txdatanonzero` |      68 | Lượng gas thanh toán cho mỗi byte khác 0 của dữ liệu hoặc mã cho một giao dịch                                         |
| `G_transaction`   |   21000 | Lượng gas thanh toán cho mỗi giao dịch                                                                                 |
| `G_log`           |     375 | Khoản thanh toán một phần cho một hoạt động `LOG`                                                                      |
| `G_logdata`       |       8 | Lượng gas thanh toán cho mỗi byte trong dữ liệu của một hoạt động `LOG`                                                |
| `G_logtopic`      |     375 | Lượng gas thanh toán cho mỗi chủ đề của một hoạt động `LOG`                                                            |
| `G_sha3`          |      30 | Lượng gas thanh toán cho từng hoạt động `SHA3`                                                                         |
| `G_sha3word`      |       6 | Lượng gas thanh toán cho từng từ (được làm tròn) cho dữ liệu nhập vào một hoạt động `SHA3`                             |
| `G_copy`          |       3 | Thanh toán một phần cho các hoạt động `COPY`, nhân lên theo số từ được sao chép, được làm tròn                         |
| `G_extcodehash`   |     700 | Được trả cho việc nhận hàm băm `keccak256` của mã hợp đồng                                                             |
| `G_create2`       |   32000 | Được trả cho mã vận hành `CREATE2`, hoạt động giống hệt như CREATE nhưng dùng những đối số khác                        |

Chúng tôi xác định những tập hợp con gồm những chỉ thị sau:

```
# ecrecover, sha256hash, ripemd160hash, dataCopy
Gas = XXXBaseGas + (number of words * XXXPerWordGas)

#### Chi phí gas <a id="gas-cost"></a>

Hàm chi phí gas chung, `C`, được xác định như sau:

#### Gas calculation during contract execution <a id="gas-calculation-during-contract-execution"></a>
The gas cost of one transaction is calculated through the methods described below. First, gas is added according to the transaction type and input. Then, if the contract is executed, opcodes are executed one by one until the execution ends or `STOP` operation appears. In the process, the cost is charged according to the `constantGas` defined for each opcode and the additionally defined gas calculation method.

Here, I will briefly explain the gas calculation logic during contract execution using the fee schedule variables defined above. As this explanation assumes a general situation, the unusual situations such as revert appears is not considered.

* add `constantGas` defined in each opcode to gas
  * e.g. if an opcode is `MUL`, add `G_low` to gas
  * e.g. if an opcode is `CREATE2`, add `G_create` to gas
* add the gas which is calculated through additionally defined gas calculation method
  * For `LOG'N'`, where N is [0,1,2,3,4], add `G_log + memoryGasCost * g_logdata + N x G_logtopic` to gas
  * For `EXP`, add `G_exp + byteSize(stack.back(1)) x G_expbyte` to gas
  * For `CALLDATACOPY` or `CODECOPY` or `RETURNDATACOPY`, add `wordSize(stack.back(2)) x G_copy` to gas
  * For `EXTCODECOPY`,
    * add `wordSize(stack.back(3)) x G_copy` to gas
    * [**_eip2929_**] If an address is not in AccessList, add it to accessList and add `G_coldSloadCost - G_warmStorageReadCost` to gas
  * For `EXTCODESIZE` or `EXTCODEHASH` or `BALANCE`,
    * [**_eip2929_**] If an address is not in AccessList, add it to accessList and add `G_coldSloadCost - G_warmStorageReadCost` to gas
  * For `SHA3`, add `G_sha3 + wordSize(stack.back(1)) x G_sha3word` to gas
  * For `RETURN`, `REVERT`, `MLoad`, `MStore8`, `MStore`, add `memoryGasCost` to gas
  * For `CREATE`, add `memoryGasCost + size(contract.code) x G_codedeposit` to gas
  * For `CREATE2`, add `memoryGasCost + size(data) x G_sha3word + size(contract.code) x G_codedeposit` to gas
  * For `SSTORE`,
    * [**_eip2929_**]  If a slot(contractAddr, slot) is not in AccessList, add it to accessList and add `G_coldSloadCost` to gas
    * If it just reads the slot (no-op), add `G_warmStorageReadCost` to gas
    * If it creates a new slot, add `G_sset` to gas
    * If it deletes the slot, add `G_sreset-G_coldSloadCost` to gas and add `R_sclear` to refund
    * If it recreates the slot once exists before, add `G_warmStorageReadCost` to gas and subtract `R_sclear` from refund
    * If it deletes the slot once exists before, add `R_sclear` to refund
    * If it resets to the original inexistent slot, add `G_warmStorageReadCost` to gas and add `G_sset - G_warmStorageReadCost` to refund
    * IF it resets to the original existing slot, add `G_warmStorageReadCost` to gas and add `G_sreset - G_coldSloadCost - G_warmStorageReadCost` to refund
  * For `SLOAD`,
    * [**_eip2929_**] If a slot(contractAddr, slot) is not in AccessList, add it to accessList and add `G_coldSloadCost` to gas
    * [**_eip2929_**] If a slot(contractAddr, slot) is in AccessList, add `G_warmStorageReadCost` to gas
  * For `CALL`, `CALLCODE`, `DELEGATECALL`, `STATICCALL`,
    * [**_eip2929_**] If an address is not in AccessList, add it to accessList and add `G_coldSloadCost` to gas
    * if it is `CALL` and `CALLCODE` and if it transfers value, add `G_callvalue` to gas
    * if it is `CALL` and if it transfers value and if it is a new account, add `G_newaccount` to gas
    * if the callee contract is precompiled contracts, calculate precompiled contract gas cost and add it to gas
    * add `memoryGasCost + availableGas - availableGas/64, where availableGas = contract.Gas - gas` to gas
  * For `SELFDESTRUCT`,
    * [**_eip2929_**] If an address is not in AccessList, add it to accessList and add `G_coldSloadCost` to gas
    * if it transfers value and if is a new account, add `G_newaccount` to gas

### Môi trường thực thi <a id="execution-environment"></a>

  if `w == CALLDATACOPY || CODECOPY || RETURNDATACOPY`

* `G_extcode + G_copy x ceil(S_machine,sp[3] / 32)`,

  if `w == EXTCODECOPY`

* `G_log + G_logdata x S_machine,sp[1]`,

  if `w == LOG0`

* `G_log + G_logdata x S_machine,sp[1] + G_logtopic`,

  if `w == LOG1`

* `G_log + G_logdata x S_machine,sp[1] + 2 x G_logtopic`,

  if `w == LOG2`

* `G_log + G_logdata x S_machine,sp[1] + 3 x G_logtopic`,

  if `w == LOG3`

* `G_log + G_logdata x S_machine,sp[1] + 4 x G_logtopic`,

  if `w == LOG4`

* `C_CALL(S_system, S_machine)`,

  if `w == CALL || CALLCODE || DELEGATECALL`

* `C_SELFDESTRUCT(S_system, S_machine)`,

  if `w == SELFDESTRUCT`

* `G_create`, if `w == CREATE`
* `G_sha3 + G_sha3word x ceil(s[1] / 32)`,

  if `w == SHA3`

* `G_jumpdest`, if `w == JUMPDEST`
* `G_sload`, if `w == SLOAD`
* `G_zero`, if `w` in `W_zero`
* `G_base`, if `w` in `W_base`
* `G_verylow`, if `w` in `W_verylow`
* `G_low`, if `w` in `W_low`
* `G_mid`, if `w` in `W_mid`
* `G__high</sub>`, if `w` in `W_high`
* `G_extcode`, if `w` in `W_extcode`
* `G_balance`, if `w == BALANCE`
* `G_blockhash`, if `w == BLOCKHASH`
* where `w` is
  * `T_code[S_machine,pc]`,

    if `S_machine,pc < length(T_code)`

  * `STOP`, otherwise
* where `C_mem(a) := G_memory x a + floor(a^2 / 512)`

với `C_CALL`, `C_SELFDESTRUCT` và `C_SSTORE` sẽ được mô tả trong tương lai.

### Môi trường thực thi <a id="execution-environment"></a>

Môi trường thực thi có chứa trạng thái hệ thống `S_system`, lượng gas còn lại để tính toán `G_rem` và thông tin `I` mà tác nhân thực thi cung cấp. `I` là một tuple được định nghĩa như dưới đây:

`I := (B_header, T_code, T_depth, T_value, T_data, A_tx_sender, A_code_executor, A_code_owner, G_price, P_modify_state)`

Mô hình thực thi xác định hàm `F_apply`, hàm này có thể tính toán trạng thái tổng hợp `S_system`, lượng gas còn lại `G_rem`, trạng thái con tích lũy `A` và dữ liệu đầu ra tổng hợp `O_result` khi đưa ra các định nghĩa này. Với bối cảnh hiện tại, chúng tôi sẽ định nghĩa như sau:

`(S_system', G_rem', A, O_result) = F_apply(S_system, G_rem, I)`

trong đó, chúng ta phải nhớ rằng `A`, trạng thái con tích lũy, được định nghĩa như một tuple gồm các tập loại bỏ `Set_suicide`, chuỗi bản ghi `L`, các tài khoản chịu ảnh hưởng `Set_touched_tài khoảns` và khoản hoàn tiền `G_refund`:

`A := (Set_suicide, L, Set_touched_tài khoảns, G_refund)`

### Tổng quan về thực thi <a id="execution-overview"></a>

Trong hầu hết những lần triển khai thực tế, `F_apply` sẽ đóng vai trò tiến trình lặp mẫu của cặp trạng thái hệ thống đầy đủ `S_system` và trạng thái máy `S_machine`. Chúng tôi chính thức định nghĩa theo cách đệ quy bằng hàm `X`, hàm này sử dụng hàm lặp `O` \(xác định kết quả của một chu kỳ duy nhất của máy trạng thái\) cùng với các hàm `Z`, hàm này xác định xem trạng thái hiện tại có phải là trạng máy tạm dừng ngoại lệ hay không và `H` chỉ định dữ liệu đầu ra của một chỉ thị nếu và chỉ nếu trạng thái hiện tại là trạng thái máy tạm dừng bình thường.

Dãy rỗng, được ký hiệu là `()`, không tương đương với tập hợp rỗng, được ký hiệu là `Set_empty`; điều này rất quan trọng khi diễn giải dữ liệu đầu ra của `H`, dữ liệu đầu ra này sẽ ước lượng thành `Set_empty` khi quá trình thực thi tiếp tục, nhưng nó sẽ trở thành chuỗi \(có khả năng rỗng\) khi quá trình thực thi tạm dừng.

`F_apply(S_machine, G_rem, I, T) := (S_system', S_machine,g', A, o)`

* `(S_system', S_machine,g', A, ..., o) := X((S_system, S_machine, A^0, I))`
* `S_machine,g := G_rem`
* `S_machine,pc := 0`
* `S_machine,memory := (0, 0, ...)`
* `S_machine,i := 0`
* `S_machine,stack := ()`
* `S_machine,o := ()`
* `X((S_system, S_machine, A, I)) :=`
  * `(Set_empty, S_machine, A^0, I, Set_empty)` if `Z(S_system, S_machine, I)`
  * `(Set_empty, S_machine', A^0, I, o)` if `w = REVERT`
  * `O(S_system, S_machine, A, I) · o` if `o != Set_empty`
  * `X(O(S_system, S_machine, A, I))` otherwise

where

* `o := H(S_machine, I)`
* `(a, b, c, d) · e := (a, b, c, d, e)`
* `S_machine' := S_machine` except

  `S_machine,g' := S_machine,g - C(S_system, S_machine, I)`

  * Điều này có nghĩa là khi chúng ta ước tính `F_apply`, chúng ta

    trích phần gas còn lại `S_machine,g'` từ

    trạng thái máy tổng hợp `S_machine'`.

Do đó, `X` được quay vòng \(ở đây là đệ quy, nhưng việc triển khai thường phải sử dụng một vòng lặp đơn giản\) cho đến khi `Z` trở thành đúng, cho biết trạng thái hiện tại là ngoại lệ, rằng máy phải tạm dừng và mọi thay đổi sẽ bị hủy hoặc cho đến khi `H` trở thành một chuỗi \(thay vì một tập hợp rỗng\), cho biết máy đã đạt đến trạng thái tạm dừng có kiểm soát.

#### Trạng thái của máy <a id="machine-state"></a>

Trạng thái của máy `S_machine` được định nghĩa là một tuple `(g, pc, memory, i, stack)`, thể hiện lượng gas khả dụng, bộ đếm chương trình `pc` \(số nguyên không dấu 64 bit\), nội dung bộ nhớ, số lượng từ đang hoạt động trong bộ nhớ \(đếm liên tục từ vị trí 0\) và nội dung của ngăn xếp dữ liệu. Nội dung bộ nhớ `S_machine,memory` là một chuỗi các số 0 có kích thước 2^256.

Để dễ đọc, phần thủ thuật ghi nhớ chỉ thị ghi bằng chữ hoa nhỏ \(_ví dụ_: `ADD`\) nên được hiểu là chỉ số đương lượng của chúng; bảng chỉ thị đầy đủ và chi tiết cụ thể của chúng được nêu trong phần [Bộ chỉ thị](klaytn-virtual-machine.md#instruction-set).

Để xác định `Z`, `H` và `O`, chúng tôi xác định `w` là hoạt động hiện tại cần được thực thi:

* `w := T_code[S_machine,pc]` if `S_machine,pc < len(T_code)`
* `w :=STOP` otherwise

### Bộ chỉ thị <a id="instruction-set"></a>

LƯU Ý: Mục này sẽ được bổ sung sau.

## KLVM khác với EVM như thế nào <a id="how-klvm-differs-from-evm"></a>

Như đã đề cập từ trước, KLVM hiện tại dựa theo EVM; vì thế, thông số kỹ thuật của nó hiện rất giống với EVM. Một số điểm khác nhau giữa KLVM và EVM được liệt kê dưới đây.

* KLVM dùng đơn vị gas của Klaytn, ví dụ như peb, ston hoặc KLAY.
* KLVM không chấp nhận giá gas từ người dùng; thay vào đó, nó dùng một giá trị được nền tảng xác định làm giá gas.

Đội ngũ Klaytn sẽ cố gắng duy trì khả năng tương thích giữa KLVM và EVM, nhưng khi Klaytn được triển khai ngày càng nhiều và phát triển, thông số kỹ thuật của KLVM sẽ được cập nhật và có thể sẽ có nhiều điểm khác biệt hơn so với EVM.

LƯU Ý: Mục này sẽ được cập nhật trong tương lai.

```


# Máy ảo Klaytn (Các tài liệu trước)

## Tổng quan <a href="#overview" id="overview"></a>

Phiên bản hiện tại của Máy ảo Klaytn (KLVM) có nguồn gốc từ Máy ảo Ethereum (EVM). Nội dung của chương này chủ yếu dựa theo [Ethereum Yellow Paper](https://github.com/ethereum/yellowpaper). KLVM liên tục được cải thiện bởi đội ngũ Klaytn, vì thế, tài liệu này có thể được cập nhật thường xuyên. Vui lòng không coi tài liệu này là phiên bản cuối cùng về thông số kỹ thuật của KLVM. Như đã được mô tả trong tuyên bố lập trường, đội ngũ Klaytn cũng có dự định áp dụng các máy ảo khác hoặc môi trường thực thi khác nhằm củng cố khả năng và hiệu suất của nền tảng Klaytn. Chương này đề cập đến thông số kỹ thuật của KLVM và sự khác biệt giữa KLVM và EVM.

KLVM là một cỗ máy trạng thái ảo, chính thức chỉ định mô hình thực thi của Klaytn. Mô hình thực thi này chỉ định cách thay đổi trạng thái hệ thống dựa trên một loạt chỉ thị bytecode và một tuple dữ liệu môi trường nhỏ. KLVM là một cỗ máy gần giống với Turing Complete, tính chất *gần giống* này bắt nguồn từ một thực tế là việc tính toán chịu sự ràng buộc nội tại qua một tham số, *gas*, tham số này hạn chế tổng lượng tính toán được thực hiện.

KLVM thực thi mã máy ảo Klaytn (hoặc bytecode Klaytn), trong đó có chứa một chuỗi các hướng dẫn KLVM. Mã KLVM là ngôn ngữ lập trình được dùng cho các tài khoản trên chuỗi khối Klaytn có chứa mã. Mã KLVM liên kết với một tài khoản được thực thi mỗi lần có một tin nhắn được gửi đến tài khoản đó; mã này có khả năng đọc/viết dữ liệu từ/vào lưu trữ và gửi tin nhắn.

## Thông số kỹ thuật của KLVM <a href="#klvm-specification" id="klvm-specification"></a>

### Các quy tắc <a href="#conventions" id="conventions"></a>

Trong tài liệu này, chúng tôi sử dụng các ký hiệu và quy tắc sau.

* `A := B`
  * `:=` được dùng để xác định `A` là `B`.
* Chúng tôi sử dụng thuật ngữ "hợp đồng thông minh" và "hợp đồng" thay thế lẫn nhau.

### Ký hiệu <a href="#symbols" id="symbols"></a>

Bảng dưới đây tóm tắt các ký hiệu được dùng trong thông số kỹ thuật của KLVM.

#### Các ký hiệu liên quan đến chuỗi khối <a href="#blockchain-related-symbols" id="blockchain-related-symbols"></a>

| Ký hiệu    | Mô tả                          |
| ---------- | ------------------------------ |
| `BC`       | Chuỗi khối                     |
| `B`        | Khối                           |
| `B_header` | Tiêu đề khối của khối hiện tại |

#### Các ký hiệu liên quan đến trạng thái <a href="#state-related-symbols" id="state-related-symbols"></a>

| Ký hiệu          | Mô tả                                         |
| ---------------- | --------------------------------------------- |
| `S`              | Trạng thái                                    |
| `S_system`       | Trạng thái của hệ thống                       |
| `S_machine`      | Trạng thái của máy                            |
| `P_modify_state` | Quyền được phép thực hiện thay đổi trạng thái |

#### Các ký hiệu liên quan đến giao dịch <a href="#transaction-related-symbols" id="transaction-related-symbols"></a>

| Ký hiệu   | Mô tả                                                                                                                                                              |
| --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `T`       | Giao dịch                                                                                                                                                          |
| `T_code`  | Một mảng byte chứa mã máy cần thực thi                                                                                                                             |
| `T_data`  | Một mảng byte chứa dữ liệu đầu vào để thực thi; nếu tác nhân thực thi là một giao dịch, dữ liệu này sẽ là dữ liệu giao dịch.                                       |
| `T_value` | Một giá trị tình bằng peb được đưa vào tài khoản như một phần của quy trình thực thi; nếu tác nhân thực thi là một giao dịch, giá trị này sẽ là giá trị giao dịch. |
| `T_depth` | Độ sâu của ngăn xếp dữ liệu tin nhắn-cuộc gọi hoặc tạo hợp đồng (*nghĩa là* số lượng `CALL` hoặc `CREATE` đang được thực thi ở thời điểm hiện tại)                 |

#### Các ký hiệu liên quan đến gas <a href="#gas-related-symbols" id="gas-related-symbols"></a>

| Ký hiệu   | Mô tả                                              |
| --------- | -------------------------------------------------- |
| `G`       | Gas                                                |
| `G_rem`   | Lượng gas còn lại để tính toán                     |
| `G_price` | Giá gas trong giao dịch phát sinh từ việc thực thi |

#### Các ký hiệu liên quan đến địa chỉ <a href="#address-related-symbols" id="address-related-symbols"></a>

| Ký hiệu           | Mô tả                                                                                                                              |
| ----------------- | ---------------------------------------------------------------------------------------------------------------------------------- |
| `A`               | Địa chỉ                                                                                                                            |
| `A_code_owner`    | Địa chỉ của tài khoản sở hữu mã thực thi                                                                                           |
| `A_tx_sender`     | Địa chỉ người gửi của giao dịch phát sinh từ việc thực thi hiện tại                                                                |
| `A_code_executor` | địa chỉ của tài khoản bắt đầu việc thực thi mã; nếu tác nhân thực thi là một giao dịch, địa chỉ này sẽ là của người gửi giao dịch. |

#### Hàm <a href="#functions" id="functions"></a>

|  Ký hiệu  | Mô tả                                                                                                                           |
| :-------: | ------------------------------------------------------------------------------------------------------------------------------- |
| `F_apply` | Một hàm áp dụng một giao dịch kèm dữ liệu đầu vào cho một trạng thái cho trước và trả về trạng thái tổng hợp kèm dữ liệu đầu ra |

### Cơ bản <a href="#basics" id="basics"></a>

KLVM là một kiến trúc dựa trên ngăn xếp dữ liệu đơn giản. Kích thước từ của máy (cũng là kích thước của các mục trong ngăn xếp dữ liệu) là 256 bit. Con số này được chọn để tạo điều kiện thuận lợi cho hệ thống hàm băm Keccak-256 và các tính toán đường cong elip. Mô hình bộ nhớ là một mảng byte chứa từ có gắn địa chỉ đơn giản. Ngăn xếp dữ liệu có kích thước tối đa là 1024. Máy cũng có một mô hình lưu trữ độc lập; về khái niệm thì nó cũng giống như bộ nhớ, nhưng thay vì một mảng byte, nó là một mảng từ với khả năng xác định địa chỉ từ. Khác với bộ nhớ mang tính biến động, lưu trữ không biến động và được duy trì như một phần của trạng thái hệ thống. Tất cả các vị trí trong lưu trữ và bộ nhớ đều được xác định bằng 0 ngay từ đầu.

Máy không tuân theo kiến trúc von Neumann tiêu chuẩn. Thay vì lưu trữ mã chương trình trong một bộ nhớ hoặc lưu trữ dễ truy cập, mã được lữu trữ riêng trong một bộ nhớ ảo chỉ đọc và chỉ có thể được tương tác qua các chỉ thị chuyên biệt.

Máy có thể thực thi mã ngoại lệ vì một số lí do, bao gồm hiện tượng tràn dưới ngăn xếp và chỉ thị không hợp lệ. Tương tự như trường hợp ngoại lệ hết gas, những ngoại lệ này không giữ nguyên các thay đổi về trạng thái. Thay vào đó, máy ảo sẽ tạm dừng ngay lập tức và báo cáo vấn đề cho tác nhân thực thi (trình xử lý giao dịch hoặc theo cách đệ quy, môi trường thực thi phát sinh), việc này sẽ được xử lý riêng biệt.

### Tổng quan về phí <a href="#fees-overview" id="fees-overview"></a>

Phí (được ghi bằng gas) được tính trong ba trường hợp riêng biệt, cả ba trường hợp đều là điều kiện tiên quyết để thực thi hoạt động. Trường hợp đầu tiên và phổ biến nhất là phí nội tại để tính toán hoạt động. Trường hợp thứ hai, gas có thể được trừ để hình thành một khoản thanh toán cho một cuộc gọi tin nhắn phụ thuộc hoặc tạo hợp đồng; đây là một phần trong khoản thanh toán dành cho `CREATE`, `CALL` và `CALLCODE`. Cuối cùng, gas có thể được tính do có sự tăng lên trong việc sử dụng bộ nhớ.

Trong quá trình thực thi tài khoản, tổng phí phải trả cho việc sử dụng bộ nhớ phải trả tỷ lệ thuận với bội số nhỏ nhất của 32 byte cần có để bao gồm tất cả các chỉ báo bộ nhớ (dù là để đọc hay để ghi) trong phạm vi. Phí này được thanh toán dựa trên cơ sở kịp thời; do đó, việc tham chiếu một vùng bộ nhớ có kích thước lớn hơn ít nhất 32 byte so với bất kỳ bộ nhớ nào khác được lập chỉ mục trước đó sẽ dẫn đến phí sử dụng bộ nhớ bổ sung. Do phí này, các địa chỉ ít có khả năng vượt quá giới hạn 32 bit. Như vậy nghĩa là việc triển khai phải có khả năng kiểm soát được tình huống này.

Phí lưu trữ có cách vận hành hơi khác biệt. Để khuyến khích việc giảm thiểu sử dụng bộ nhớ (tương ứng trực tiếp với một cơ sở dữ liệu trạng thái lớn hơn trên tất cả các nút), phí thực thi cho một hoạt động xóa mục nhập khỏi lưu trữ sẽ được miễn phí và đủ điều kiện để nhận hoàn phí; trên thực tế, khoản hoàn phí này được thanh toán trước vì chi phí sử dụng ban đầu của một vị trí lưu trữ lại cao hơn đáng kể so với việc sử dụng thông thường.

#### Biểu phí <a href="#fee-schedule" id="fee-schedule"></a>

Biểu phí `G` là một tuple gồm 37 giá trị vô hướng, tương ứng với chi phí tương đối tính bằng gas của một số hoạt động trừu tượng mà một giao dịch có thể làm phát sinh. Để xem các bảng khác như `Precompiled contracts` và `tài khoảns`, vui lòng tham khảo [tài liệu này](/content/klaytn/design/transaction-fees#klaytns-gas-table)

{% hint style="success" %}
LƯU Ý: Tài liệu này chứa biểu phí được sử dụng trước khi kích hoạt nâng cấp giao thức. Nếu bạn muốn nhận tài liệu mới nhất, vui lòng tham khảo [tài liệu mới nhất](/content/klaytn/design/computation/klaytn-virtual-machine).
{% endhint %}

| Tên               | Giá trị | Mô tả                                                                                                                  |
| ----------------- | ------: | ---------------------------------------------------------------------------------------------------------------------- |
| `G_zero`          |       0 | Không cần thanh toán cho các hoạt động của bộ `W_zero`                                                                 |
| `G_base`          |       2 | Lượng gas thanh toán cho các hoạt động của bộ `W_base`                                                                 |
| `G_verylow`       |       3 | Lượng gas thanh toán cho các hoạt động của bộ `W_verylow`                                                              |
| `G_low`           |       5 | Lượng gas thanh toán cho các hoạt động của bộ `W_low`                                                                  |
| `G_mid`           |       8 | Lượng gas thanh toán cho các hoạt động của bộ `W_mid`                                                                  |
| `G_high`          |      10 | Lượng gas thanh toán cho các hoạt động của bộ `W_high`                                                                 |
| `G_blockhash`     |      20 | Khoản thanh toán cho một hoạt động `BLOCKHASH`                                                                         |
| `G_extcode`       |     700 | Lượng gas thanh toán cho các hoạt động của bộ `W_extcode`                                                              |
| `G_balance`       |     400 | Lượng gas thanh toán cho một hoạt động `BALANCE`                                                                       |
| `G_sload`         |     200 | Lượng gas thanh toán cho một hoạt động `SLOAD`                                                                         |
| `G_jumpdest`      |       1 | Lượng gas thanh toán cho một hoạt động `JUMPDEST`                                                                      |
| `G_sset`          |   20000 | Lượng gas thanh toán cho một hoạt động `SSTORE` khi giá trị lưu trữ được đặt từ số khác 0 sang số 0                    |
| `G_sreset`        |    5000 | Lượng gas thanh toán cho một hoạt động `SSTORE` khi giá trị lưu trữ giữ nguyên không đổi ở mức 0 hoặc được đặt thành 0 |
| `R_sclear`        |   15000 | Khoản hoàn tiền đã được thực hiện (được thêm vào bộ đếm hoàn tiền) khi giá trị lưu trữ được đặt từ số khác 0 sang số 0 |
| `R_selfdestruct`  |   24000 | Khoản hoàn tiền đã thực hiện (được thêm vào bộ đếm hoàn tiền) cho việc tự hủy một tài khoản                            |
| `G_selfdestruct`  |    5000 | Lượng gas thanh toán cho một hoạt động `SELFDESTRUCT`                                                                  |
| `G_create`        |   32000 | Lượng gas thanh toán cho một hoạt động `CREATE`                                                                        |
| `G_codedeposit`   |     200 | Lượng gas thanh toán cho mỗi byte cho một hoạt động `CREATE` thành công trong việc đặt mã vào trạng thái               |
| `G_call`          |     700 | Lượng gas thanh toán cho một hoạt động `CALL`                                                                          |
| `G_callvalue`     |    9000 | Lượng gas thanh toán một giao dịch chuyển giá trị khác 0 như một phần của hoạt động `CALL`                             |
| `G_callstipend`   |    2300 | Khoản trợ cấp cho hợp đồng được gọi ra, được trừ khỏi `G_callvalue` đối với giao dịch chuyển giá trị khác 0            |
| `G_newtài khoản`  |   25000 | Lượng gas thanh toán cho một hoạt động `CALL` hoặc `SELFDESTRUCT` tạo ra một tài khoản                                 |
| `G_exp`           |      10 | Khoản thanh toán một phần cho một hoạt động `EXP`                                                                      |
| `G_expbyte`       |      50 | Khoản thanh toán một phần khi nhân với `ceil(log_256(exponent))` cho một hoạt động `EXP`                               |
| `G_memory`        |       3 | Lượng gas thanh toán cho mỗi một từ bổ sung khi mở rộng bộ nhớ                                                         |
| `G_txcreate`      |   32000 | Lượng gas được trả bởi tất cả các giao dịch tạo hợp đồng                                                               |
| `G_txdatazero`    |       4 | Lượng gas thanh toán cho mỗi byte 0 của dữ liệu hoặc mã cho một giao dịch                                              |
| `G_txdatanonzero` |      68 | Lượng gas thanh toán cho mỗi byte khác 0 của dữ liệu hoặc mã cho một giao dịch                                         |
| `G_transaction`   |   21000 | Lượng gas thanh toán cho mỗi giao dịch                                                                                 |
| `G_log`           |     375 | Khoản thanh toán một phần cho một hoạt động `LOG`                                                                      |
| `G_logdata`       |       8 | Lượng gas thanh toán cho mỗi byte trong dữ liệu của một hoạt động `LOG`                                                |
| `G_logtopic`      |     375 | Lượng gas thanh toán cho mỗi chủ đề của một hoạt động `LOG`                                                            |
| `G_sha3`          |      30 | Lượng gas thanh toán cho từng hoạt động `SHA3`                                                                         |
| `G_sha3word`      |       6 | Lượng gas thanh toán cho từng từ (được làm tròn) cho dữ liệu nhập vào một hoạt động `SHA3`                             |
| `G_copy`          |       3 | Thanh toán một phần cho các hoạt động `COPY`, nhân lên theo số từ được sao chép, được làm tròn                         |
| `G_extcodehash`   |     400 | Được trả cho việc nhận hàm băm `keccak256` của mã hợp đồng                                                             |
| `G_create2`       |   32000 | Được trả cho mã vận hành `CREATE2`, hoạt động giống hệt như CREATE nhưng dùng những đối số khác                        |

Chúng tôi xác định những tập hợp con gồm những chỉ thị sau:

For example, gas cost can be calculated simply like below, but some gas cost calculation functions are very complex. So I would not explain the exact gas cost calculation function here.

#### Chi phí gas <a href="#gas-cost" id="gas-cost"></a>

Hàm chi phí gas chung, `C`, được xác định như sau:

| Address | Precompiled contracts | Item                                         | Value        |
| ------- | --------------------- | -------------------------------------------- | ------------ |
| 0x01    | ecrecover             | EcrecoverGas                                 | 3000         |
| 0x02    | sha256hash            | Sha256BaseGas, Sha256PerWordGas              | 60, 12       |
| 0x03    | ripemd160hash         | Ripemd160BaseGas, Ripemd160PerWordGas        | 600, 120     |
| 0x04    | dataCopy              | IdentityBaseGas, IdentityPerWordGas          | 15, 3        |
| 0x05    | bigModExp             | ModExpQuadCoeffDiv                           | 20           |
| 0x06    | bn256Add              | Bn256AddGas                                  | 150          |
| 0x07    | bn256ScalarMul        | Bn256ScalarMulGas                            | 6000         |
| 0x08    | bn256Pairing          | Bn256PairingBaseGas, Bn256PairingPerPointGas | 45000, 34000 |
| 0x09    | vmLog                 | VMLogBaseGas, VMLogPerByteGas                | 100, 20      |
| 0x10    | feePayer              | FeePayerGas                                  | 300          |
| 0x11    | validateSender        | ValidateSenderGas                            | 5000         |

#### Gas calculation during contract execution <a href="#gas-calculation-during-contract-execution" id="gas-calculation-during-contract-execution"></a>

The gas cost of one transaction is calculated through the methods described below. First, gas is added according to the transaction type and input. Then, if the contract is executed, opcodes are executed one by one until the execution ends or `STOP` operation appears. In the process, the cost is charged according to the `constantGas` defined for each opcode and the additionally defined gas calculation method.

Below is a brief explanation of the gas calculation logic during contract execution using the fee schedule variables defined above. As it assumes a general situation, unusual situations such as revert appears is not considered.

* add `constantGas` defined in each opcode to gas
  * e.g. if an opcode is `MUL`, add `G_low` to gas
  * e.g. if an opcode is `CREATE2`, add `G_create` to gas
* add the gas which is calculated through additionally defined gas calculation method
  * For `LOG'N'`, where N is \[0,1,2,3,4], add `G_log + memoryGasCost * g_logdata + N x G_logtopic` to gas
  * For `EXP`, add `G_exp + byteSize(stack.back(1)) x G_expbyte` to gas
  * For `CALLDATACOPY` or `CODECOPY` or `RETURNDATACOPY`, add `wordSize(stack.back(2)) x G_copy` to gas
  * For `EXTCODECOPY`, add `wordSize(stack.back(3)) x G_copy` to gas
  * For `SHA3`, add `G_sha3 + wordSize(stack.back(1)) x G_sha3word` to gas
  * For `RETURN`, `REVERT`, `MLoad`, `MStore8`, `MStore`, add `memoryGasCost` to gas
  * For `CREATE`, add `memoryGasCost + size(contract.code) x G_codedeposit`
  * For `CREATE2`, add `memoryGasCost + size(data) x G_sha3word + size(contract.code) x G_codedeposit` to gas
  * For `SSTORE`,
    * From a zero-value address to a non-zero value (NEW VALUE), add `G_sset` to gas
    * From a non-zero value address to a zero-value address (DELETE), add `G_sreset` to gas and add `R_sclear` to refund
    * From a non-zero to a non-zero (CHANGE), add `G_sreset` to gas
  * For `CALL`, `CALLCODE`, `DELEGATECALL`, `STATICCALL`,
    * if it is `CALL` and `CALLCODE` and if it transfers value, add `G_callvalue` to gas
    * if it is `CALL` and if it transfers value and if it is a new account, add `G_newaccount` to gas
    * if the callee contract is precompiled contracts, calculate precompiled contract gas cost and add it to gas
    * add `memoryGasCost + availableGas - availableGas/64, where availableGas = contract.Gas - gas` to gas
  * For `SELFDESTRUCT`,
    * if it transfers value and if is a new account, add `G_newaccount` to gas
    * if the contract has not suicided yet, add `R_selfdestruct` to refund

### Môi trường thực thi <a href="#execution-environment" id="execution-environment"></a>

* `G_extcode + G_copy x ceil(S_machine,sp[3] / 32)`,

  if `w == EXTCODECOPY`
* `G_log + G_logdata x S_machine,sp[1]`,

  if `w == LOG0`
* `G_log + G_logdata x S_machine,sp[1] + G_logtopic`,

  if `w == LOG1`
* `G_log + G_logdata x S_machine,sp[1] + 2 x G_logtopic`,

  if `w == LOG2`
* `G_log + G_logdata x S_machine,sp[1] + 3 x G_logtopic`,

  if `w == LOG3`
* `G_log + G_logdata x S_machine,sp[1] + 4 x G_logtopic`,

  if `w == LOG4`
* `C_CALL(S_system, S_machine)`,

  if `w == CALL || CALLCODE || DELEGATECALL`
* `C_SELFDESTRUCT(S_system, S_machine)`,

  if `w == SELFDESTRUCT`
* `G_create`, if `w == CREATE`
* `G_sha3 + G_sha3word x ceil(s[1] / 32)`,

  if `w == SHA3`
* `G_jumpdest`, if `w == JUMPDEST`
* `G_sload`, if `w == SLOAD`
* `G_zero`, if `w` in `W_zero`
* `G_base`, if `w` in `W_base`
* `G_verylow`, if `w` in `W_verylow`
* `G_low`, if `w` in `W_low`
* `G_mid`, if `w` in `W_mid`
* `G__high</sub>`, if `w` in `W_high`
* `G_extcode`, if `w` in `W_extcode`
* `G_balance`, if `w == BALANCE`
* `G_blockhash`, if `w == BLOCKHASH`
* where `w` is
  * `T_code[S_machine,pc]`,

    if `S_machine,pc < length(T_code)`
  * `STOP`, otherwise
* where `C_mem(a) := G_memory x a + floor(a^2 / 512)`

với `C_CALL`, `C_SELFDESTRUCT` và `C_SSTORE` sẽ được mô tả trong tương lai.

### Môi trường thực thi <a href="#execution-environment" id="execution-environment"></a>

Môi trường thực thi có chứa trạng thái hệ thống `S_system`, lượng gas còn lại để tính toán `G_rem` và thông tin `I` mà tác nhân thực thi cung cấp. `I` là một tuple được định nghĩa như dưới đây:

`I := (B_header, T_code, T_depth, T_value, T_data, A_tx_sender, A_code_executor, A_code_owner, G_price, P_modify_state)`

Mô hình thực thi xác định hàm `F_apply`, hàm này có thể tính toán trạng thái tổng hợp `S_system`, lượng gas còn lại `G_rem`, trạng thái con tích lũy `A` và dữ liệu đầu ra tổng hợp `O_result` khi đưa ra các định nghĩa này. Với bối cảnh hiện tại, chúng tôi sẽ định nghĩa như sau:

`(S_system', G_rem', A, O_result) = F_apply(S_system, G_rem, I)`

trong đó, chúng ta phải nhớ rằng `A`, trạng thái con tích lũy, được định nghĩa như một tuple gồm các tập loại bỏ `Set_suicide`, chuỗi bản ghi `L`, các tài khoản chịu ảnh hưởng `Set_touched_tài khoảns` và khoản hoàn tiền `G_refund`:

`A := (Set_suicide, L, Set_touched_tài khoảns, G_refund)`

### Tổng quan về thực thi <a href="#execution-overview" id="execution-overview"></a>

Trong hầu hết những lần triển khai thực tế, `F_apply` sẽ đóng vai trò tiến trình lặp mẫu của cặp trạng thái hệ thống đầy đủ `S_system` và trạng thái máy `S_machine`. Chúng tôi chính thức định nghĩa theo cách đệ quy bằng hàm `X`, hàm này sử dụng hàm lặp `O` (xác định kết quả của một chu kỳ duy nhất của máy trạng thái) cùng với các hàm `Z`, hàm này xác định xem trạng thái hiện tại có phải là trạng máy tạm dừng ngoại lệ hay không và `H` chỉ định dữ liệu đầu ra của một chỉ thị nếu và chỉ nếu trạng thái hiện tại là trạng thái máy tạm dừng bình thường.

Dãy rỗng, được ký hiệu là `()`, không tương đương với tập hợp rỗng, được ký hiệu là `Set_empty`; điều này rất quan trọng khi diễn giải dữ liệu đầu ra của `H`, dữ liệu đầu ra này sẽ ước lượng thành `Set_empty` khi quá trình thực thi tiếp tục, nhưng nó sẽ trở thành chuỗi (có khả năng rỗng) khi quá trình thực thi tạm dừng.

`F_apply(S_machine, G_rem, I, T) := (S_system', S_machine,g', A, o)`

* `(S_system', S_machine,g', A, ..., o) := X((S_system, S_machine, A^0, I))`
* `S_machine,g := G_rem`
* `S_machine,pc := 0`
* `S_machine,memory := (0, 0, ...)`
* `S_machine,i := 0`
* `S_machine,stack := ()`
* `S_machine,o := ()`
* `X((S_system, S_machine, A, I)) :=`
  * `(Set_empty, S_machine, A^0, I, Set_empty)` if `Z(S_system, S_machine, I)`
  * `(Set_empty, S_machine', A^0, I, o)` if `w = REVERT`
  * `O(S_system, S_machine, A, I) · o` if `o != Set_empty`
  * `X(O(S_system, S_machine, A, I))` otherwise

where

* `o := H(S_machine, I)`
* `(a, b, c, d) · e := (a, b, c, d, e)`
* `S_machine' := S_machine` except

  `S_machine,g' := S_machine,g - C(S_system, S_machine, I)`

  * Điều này có nghĩa là khi chúng ta ước tính `F_apply`, chúng ta

    trích phần gas còn lại `S_machine,g'` từ

    trạng thái máy tổng hợp `S_machine'`.

Do đó, `X` được quay vòng (ở đây là đệ quy, nhưng việc triển khai thường phải sử dụng một vòng lặp đơn giản) cho đến khi `Z` trở thành đúng, cho biết trạng thái hiện tại là ngoại lệ, rằng máy phải tạm dừng và mọi thay đổi sẽ bị hủy hoặc cho đến khi `H` trở thành một chuỗi (thay vì một tập hợp rỗng), cho biết máy đã đạt đến trạng thái tạm dừng có kiểm soát.

#### Trạng thái của máy <a href="#machine-state" id="machine-state"></a>

Trạng thái của máy `S_machine` được định nghĩa là một tuple `(g, pc, memory, i, stack)`, thể hiện lượng gas khả dụng, bộ đếm chương trình `pc` (số nguyên không dấu 64 bit), nội dung bộ nhớ, số lượng từ đang hoạt động trong bộ nhớ (đếm liên tục từ vị trí 0) và nội dung của ngăn xếp dữ liệu. Nội dung bộ nhớ `S_machine,memory` là một chuỗi các số 0 có kích thước 2^256.

Để dễ đọc, phần thủ thuật ghi nhớ chỉ thị ghi bằng chữ hoa nhỏ (*ví dụ*: `ADD`) nên được hiểu là chỉ số đương lượng của chúng; bảng chỉ thị đầy đủ và chi tiết cụ thể của chúng được nêu trong phần [Bộ chỉ thị](/content/klaytn/design/computation/klaytn-virtual-machine#instruction-set).

Để xác định `Z`, `H` và `O`, chúng tôi xác định `w` là hoạt động hiện tại cần được thực thi:

* `w := T_code[S_machine,pc]` if `S_machine,pc < len(T_code)`
* `w :=STOP` otherwise

### Bộ chỉ thị <a href="#instruction-set" id="instruction-set"></a>

LƯU Ý: Mục này sẽ được bổ sung sau.

## KLVM khác với EVM như thế nào <a href="#how-klvm-differs-from-evm" id="how-klvm-differs-from-evm"></a>

Như đã đề cập từ trước, KLVM hiện tại dựa theo EVM; vì thế, thông số kỹ thuật của nó hiện rất giống với EVM. Một số điểm khác nhau giữa KLVM và EVM được liệt kê dưới đây.

* KLVM dùng đơn vị gas của Klaytn, ví dụ như peb, ston hoặc KLAY.
* KLVM không chấp nhận giá gas từ người dùng; thay vào đó, nó dùng một giá trị được nền tảng xác định làm giá gas.

Đội ngũ Klaytn sẽ cố gắng duy trì khả năng tương thích giữa KLVM và EVM, nhưng khi Klaytn được triển khai ngày càng nhiều và phát triển, thông số kỹ thuật của KLVM sẽ được cập nhật và có thể sẽ có nhiều điểm khác biệt hơn so với EVM.

LƯU Ý: Mục này sẽ được cập nhật trong tương lai.


# Lưu trữ

## Di chuyển trạng thái <a href="#state-migration" id="state-migration"></a>

Khi càng có nhiều khối được thêm vào chuỗi khối, dữ liệu chuỗi sẽ càng tăng lên. Dữ liệu chuỗi rất cần thiết cho việc vận hành nút, vì thế chúng được lưu trữ trong kho lưu trữ nút dưới dạng cấu trúc dữ liệu, được gọi là trie và sau cùng sẽ đi vào cơ sở dữ liệu, được gọi là LevelDB. Vì thế, với nhiều khối hơn thì sẽ có nhiều dữ liệu chuỗi trong kho lữu trữ hơn, kèm theo đó là chi phí tăng lên. Vì thế, Klaytn hỗ trợ một tính năng gọi là Di chuyển trạng thái cho phép bạn giảm dung lượng lưu trữ cần thiết.

Di chuyển trạng thái nhắm đến các trie trạng thái, trong đó bao gồm hầu hết dữ liệu chuỗi. Tính năng này sẽ xóa các nút trie trạng thái không cần thiết cho việc xử lý các khối mới. Nó chỉ để lại các nút trie trạng thái có thể tiếp cận được từ gốc trie trạng thái của một khối cụ thể. Sau khi Di chuyển trạng thái, bạn chỉ còn lại những dữ liệu mới nhất cần thiết cho việc đồng bộ hóa nút, trong đó có chưa các nút trie trạng thái của khối đích và các khối mới được thêm vào. Di chuyển trạng thái nhắm đến các trie trạng thái, trong đó bao gồm hầu hết dữ liệu chuỗi. Tính năng này sẽ xóa các nút trie trạng thái không cần thiết cho việc xử lý các khối mới. Nó chỉ để lại các nút trie trạng thái có thể tiếp cận được từ gốc trie trạng thái của một khối cụ thể. Sau khi Di chuyển trạng thái, bạn chỉ còn lại những dữ liệu mới nhất cần thiết cho việc đồng bộ hóa nút, trong đó có chưa các nút trie trạng thái của khối đích và các khối mới được thêm vào.

Lưu ý rằng một nút không thể đọc được các trạng thái cũ từ các khối xuất hiện trước khối đích sau khi Di chuyển trạng thái. Nói cách khác, bạn không thể quay về số dư từ một số khối cũ bằng API `klay_getBalance` nữa.

Bạn có thể đọc thêm thông tin chi tiết về cơ chế của tính năng Di chuyển trạng thái tại: [Di chuyển trạng thái Klaytn v1.5.0: Thiết kiệm dung lượng lưu trữ nút](https://medium.com/klaytn/klaytn-v1-5-0-state-migration-saving-node-storage-1358d87e4a7a) [Di chuyển trạng thái Klaytn: Cách hiệu quả để giảm dữ liệu chuỗi khối](https://medium.com/klaytn/klaytn-state-migration-an-efficient-way-to-reduce-blockchain-data-6615a3b36523)

Để dùng tính năng Di chuyển trạng thái, vui lòng xem tài liệu về API quản trị. [`admin_startStateMigration`](https://vn.docs.klaytn.foundation/content/dapp/json-rpc/api-references/admin#admin_startstatemigration) cho phép bạn bắt đầu tính năng Di chuyển trạng thái, [`admin_stateMigrationStatus`](https://vn.docs.klaytn.foundation/content/dapp/json-rpc/api-references/admin#admin_statemigrationstatus) cho phép bạn kiểm tra trạng thái của tính năng này và [`admin_stopStateMigration`](https://vn.docs.klaytn.foundation/content/dapp/json-rpc/api-references/admin#admin_stopstatemigrationn) cho phép bạn dừng quy trình này.


# Phí giao dịch

{% hint style="success" %}
NOTE: The transaction fee has changed with the `Kore` hardfork. If you want the previous document, please refer to [previous document](/content/klaytn/design/transaction-fees/transaction-fees-previous).

`Kore` hardfork block numbers are as follows.

* Baobab Testnet: `#111736800`
* Cypress Mainnet: `#119750400`
  {% endhint %}

The transaction fee of one transaction is calculated as follows:

```
Transaction fee := (Gas used) x (GasPrice)
```

As an easy-to-understand analogy in this regard, suppose you're filling up gas at a gas station. The gas price is determined by the refinery every day, and today's price is $2. If you fill 15L up, then you would pay $30 = 15L x $2/1L for it, and the $30 will be paid out of your bank account. Also, the transaction will be recorded in the account book.

Transaction fee works just the same as above. The network determines the gas price for every block. Suppose the gas price for the current block is 30 ston. If a transaction submitted by `from` account was charged 21000 gas, then 630000 ston = (21000 gas \* 30 ston) would be paid out of the `from` account. Also, the transaction will be recorded in the block, and it will be applied in the state of all blockchain nodes.

Summing it up again, this calculated transaction fee is subtracted from the sender's or fee payer's account. However, the fee can be deducted from the balance only if the transaction is created by klay\_sendTransaction/eth\_sendTransaction. Because the other transactions cannot change the state since they cannot be included in the block. They are just a simulation in some way.

This is an overall explanation of the transaction fee, and from this point, we would give a detailed explanation of how gas price is determined and how the gas is calculated.

## Tổng quan về gas và phí cơ sở <a href="#gas-and-base-fee-overview" id="gas-and-base-fee-overview"></a>

### Gas <a href="#gas" id="gas"></a>

Mọi hành động làm thay đổi trạng thái của chuỗi khối đều cần đến gas. Khi một nút xử lý giao dịch của người dùng, ví dụ như gửi KLAY, dùng token KIP-7, hoặc thực thi một hợp đồng, người dùng phải trả phí cho việc tính toán và sử dụng dung lượng lưu trữ. Số tiền thanh toán được xác định bằng số `gas` cần dùng.

| Network  | Before BaseFee                                                                                                                      | After BaseFee                                                                                                                                                                                                             |
| -------- | ----------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| klaytn   | <p>tx parameter gasPrice: network-defined. must be set as the <code>unitPrice</code><br>gasPrice: use the tx parameter gasPrice</p> | <p>tx parameter gasPrice: user-defined. It means the price the most you can pay<br>(e.g. suggestGasPrice = 2\*latestBlock.baseFee )<br>gasPrice: dynamic gasPrice, <code>baseFee</code>, which is defined by network.</p> |
| Ethereum | <p>tx parameter gasPrice: user-defined. it means the price the most you can pay.<br>gasPrice: use the tx parameter gasPrice</p>     | <p>tx parameter gasPrice: user-defined. It means the price the most you can pay.<br>gasPrice: dynamic gasPrice, <code>baseFee+tip</code>, which is defined by network.</p>                                                |

### Cơ chế phí gas động <a href="#dynamic-gas-fee-mechanism" id="dynamic-gas-fee-mechanism"></a>

Sau khi nâng cấp căn bản Klaytn v1.9.0, một cơ chế phí gas động đã thay thế chính sách phí cố định hiện có. Chính sách phí gas động cung cấp một dịch vụ ổn định cho người dùng bằng cách ngăn chặn các hành vi lạm dụng mạng lưới và chiếm dụng dung lượng lưu trữ. Phí gas thay đổi tùy theo tình hình của mạng. Có bảy tham số ảnh hưởng đến `phí cơ sở (phí gas)`:

1. PREVIOUS\_BASE\_FEE: Phí cơ sở của khối trước đó
2. GAS\_USED\_FOR\_THE\_PREVIOUS\_BLOCK: Lượng gas dùng để xử lý tất cả các giao dịch của khối trước đó
3. GAS\_TARGET: Lượng gas quyết định việc tăng hoặc giảm phí cơ sở (hiện tại là 30 triệu)
4. MAX\_BLOCK\_GAS\_USED\_FOR\_BASE\_FEE: Hạn mức gas cho khối ẩn để thực thi tỷ lệ thay đổi phí cơ sở (hiện tại là 60 triệu)
5. BASE\_FEE\_DELTA\_REDUCING\_DENOMINATOR: Giá trị để đặt thay đổi phí cơ sở tối đa thành 5% mỗi khối (hiện tại là 20, có thể được nhóm quản trị thay đổi sau)
6. UPPER\_BOUND\_BASE\_FEE: Giá trị tối đa cho phí cơ sở (hiện tại là 750 ston, có thể được nhóm quản trị thay đổi sau)
7. LOWER\_BOUND\_BASE\_FEE: Giá trị tối thiểu cho phí cơ sở (hiện tại là 25 ston, có thể được nhóm quản trị thay đổi sau)

### Base Fee <a href="#base-fee" id="base-fee"></a>

The basic idea of this algorithm is that the `base fee` would go up if the gas used exceeds the base gas and vice versa. It is closely related to the number of transactions in the network and the gas used in the process. There is an upper and lower limit for the `base fee` to prevent the fee from increasing or decreasing indefinitely. There is also a cap for the gas and an adjustment value for the fluctuation to prevent abrupt changes in the `base fee`. The values can be changed by governance.

```
(BASE_FEE_CHANGE_RATE) = (GAS_USED_FOR_THE_PREVIOUS_BLOCK - GAS_TARGET)
(ADJUSTED_BASE_FEE_CHANGE_RATE) = (BASE_FEE_CHANGE_RATE) / (GAS_TARGET) / (BASE_FEE_DELTA_REDUCING_DENOMINATOR)
(BASE_FEE_CHANGE_RANGE) = (PREVIOUS_BASE_FEE) * (ADJUSTED_BASE_FEE_CHANGE_RATE)
(BASE_FEE) = (PREVIOUS_BASE_FEE) + (BASE_FEE_CHANGE_RANGE) 
```

The `base fee` is calculated for every block; there could be changes every second. Transactions from a single block use the same `base fee` to calculate transaction fees. Only transactions with a gas price higher than the block `base fee` can be included in the block. Half of the transaction fee for each block is burned (BURN\_RATIO = 0.5, cannot be changed by governance).

> LƯU Ý: Một tính năng quan trọng khiến Klaytn trở nên khác biệt với EIP-1559 của Ethereum là nó không có phí trả thêm. Klaytn tuân theo nguyên tắc “Ai đến trước thì được phục vụ trước” (FCFS) đối với các giao dịch của mình.

## Gas Overview <a href="#gas-overview" id="gas-overview"></a>

Every action that changes the state of the blockchain requires gas. While processing the transactions in a block, such as sending KLAY, using KIP-7 tokens, or executing a contract, the user has to pay for the computation and storage usage. The payment amount is decided by the amount of `gas` required.

Klaytn hiện không cung cấp phương pháp thay thế giao dịch bằng đơn giá, nhưng có thể hỗ trợ các phương pháp thay thế giao dịch khác trong tương lai. Xin lưu ý rằng trong Ethereum, một giao dịch với một số dùng một lần nhất định có thể được thay thế bằng một giao dịch mới với giá gas cao hơn.

## Biểu giá gas của Klaytn <a href="#klaytns-gas-table" id="klaytns-gas-table"></a>

Về cơ bản, Klaytn luôn duy trì khả năng tương thích với Ethereum. Vì thế, biểu giá gas của Klaytn cũng khá tương đồng với biểu giá của Ethereum. Tuy nhiên, có một số tính năng chỉ Klaytn mới có và cần một vài hằng số mới.

{% hint style="success" %}
LƯU Ý: Bảng gas đã thay đổi cùng với việc nâng cấp giao thức `IstanbulEVM` hay còn gọi là "nâng cấp căn bản". Nếu bạn muốn đọc tài liệu trước đây, vui lòng tham khảo phần [tài liệu trước đây](/content/klaytn/design/transaction-fees/transaction-fees-previous).

Số khối nâng cấp giao thức `IstanbulEVM` như sau.

* Mạng thử nghiệm Baobab: `#75373312`
* Mạng chính thức Cypress: `#86816005`
  {% endhint %}

### Phí chung <a href="#common-fee" id="common-fee"></a>

| Mục             | Gas   | Mô tả                                                                                                              |
| --------------- | ----- | ------------------------------------------------------------------------------------------------------------------ |
| G\_zero         | 0     | Không cần thanh toán cho các hoạt động của bộ Wzero                                                                |
| G\_base         | 2     | Lượng gas phải trả cho các hoạt động của bộ Wbase                                                                  |
| G\_verylow      | 3     | Lượng gas phải trả cho các hoạt động của bộ Wverylow                                                               |
| G\_low          | 5     | Lượng gas phải trả cho các hoạt động của bộ Wlow                                                                   |
| G\_mid          | 8     | Lượng gas phải trả cho các hoạt động của bộ Wmid                                                                   |
| G\_high         | 10    | Lượng gas phải trả cho các hoạt động của bộ Whigh                                                                  |
| G\_blockhash    | 20    | Khoản thanh toán cho hoạt động BLOCKHASH                                                                           |
| G\_extcode      | 700   | Lượng gas phải trả cho các hoạt động của bộ Wextcode                                                               |
| G\_balance      | 700   | Lượng gas phải trả cho một hoạt động BALANCE                                                                       |
| G\_sload        | 800   | Được trả cho một hoạt động SLOAD                                                                                   |
| G\_jumpdest     | 1     | Được trả cho một hoạt động JUMPDEST                                                                                |
| G\_sset         | 20000 | Được trả cho một hoạt động SSTORE khi giá trị lưu trữ được đặt từ số 0 sang số khác 0                              |
| G\_sreset       | 5000  | Được trả cho một hoạt động SSTORE khi giá trị bằng không của giá trị không đổi, hoặc được đặt thành số 0           |
| G\_sclear       | 15000 | Khoản hoàn tiền đã thực hiện (được thêm vào bộ đếm hoàn tiền) khi giá trị lưu trữ được đặt từ số khác 0 thành số 0 |
| R\_selfdestruct | 24000 | Khoản hoàn tiền đã thực hiện (được thêm vào bộ đếm hoàn tiền) cho việc tự hủy một tài khoản                        |
| G\_selfdestruct | 5000  | Lượng gas phải trả cho một hoạt động SELFDESTRUCT                                                                  |
| G\_create       | 32000 | Được trả cho một hoạt động CREATE                                                                                  |
| G\_codedeposit  | 200   | Được trả theo byte cho hoạt động CREATE để thành công trong việc đặt mã vào trạng thái                             |
| G\_call         | 700   | Được trả cho một hoạt động CALL                                                                                    |
| G\_callvalue    | 9000  | Được trả cho một giao dịch chuyển giá trị khác 0 như một phần của hoạt động CALL                                   |
| G\_callstipend  | 2300  | Khoản trợ cấp cho hợp đồng được gọi ra, được trừ khỏi Gcallvalue đối với giao dịch chuyển giá trị khác 0           |
| G\_newtài khoản | 25000 | Được trả cho hoạt động CALL hoặc SELFDESTRUCT để tạo tài khoản                                                     |
| G\_exp          | 10    | Khoản thanh toán một phần cho hoạt động EXP                                                                        |
| G\_expbyte      | 50    | Khoản thanh toán một phần khi nhân với dlog256(exponent)e cho hoạt động EXP                                        |
| G\_memory       | 3     | Được trả cho mỗi một từ bổ sung khi mở rộng bộ nhớ                                                                 |
| G\_txcreate     | 32000 | Được trả bởi tất cả các giao dịch tạo hợp đồng                                                                     |
| G\_transaction  | 21000 | Được trả cho mọi giao dịch                                                                                         |
| G\_log          | 375   | Khoản thanh toán một phần cho hoạt động LOG                                                                        |
| G\_logdata      | 8     | Được trả cho mỗi byte trong dữ liệu của hoạt động LOG                                                              |
| G\_logtopic     | 375   | Được trả cho từng chủ đề của hoạt động LOG                                                                         |
| G\_sha3         | 30    | Được trả cho mỗi hoạt động SHA3                                                                                    |
| G\_sha3word     | 6     | Được trả cho từng từ (được làm tròn) cho dữ liệu nhập vào hoạt động SHA3                                           |
| G\_copy         | 3     | Thanh toán một phần cho các hoạt động \*COPY, nhân lên theo số từ được sao chép, được làm tròn                     |
| G\_blockhash    | 20    | Khoản thanh toán cho hoạt động BLOCKHASH                                                                           |
| G\_extcodehash  | 700   | Được trả cho việc nhận hàm băm keccak256 của mã hợp đồng                                                           |
| G\_create2      | 32000 | Được trả cho mã vận hành CREATE2, hoạt động giống hệt như CREATE nhưng dùng những đối số khác                      |

### Hợp đồng đã lập trước <a href="#precompiled-contracts" id="precompiled-contracts"></a>

Hợp đồng đã lập trước là loại hợp đồng đặc biệt, thường thực hiện các phép tính toán mã hóa phức tạp và được khởi tạo bởi những hợp đồng khác.

| Mục                     | Gas                 | Mô tả                                                          |
| ----------------------- | ------------------- | -------------------------------------------------------------- |
| EcrecoverGas            | 3000                | Thực hiện hoạt động ECRecover                                  |
| Sha256BaseGas           | 60                  | Thực hiện hoạt động hàm băm sha256                             |
| Sha256PerWordGas        | 12                  |                                                                |
| Ripemd160BaseGas        | 600                 | Thực hiện hoạt động Ripemd160                                  |
| Ripemd160PerWordGas     | 120                 |                                                                |
| IdentityBaseGas         | 15                  |                                                                |
| IdentityPerWordGas      | 3                   |                                                                |
| ModExpQuadCoeffDiv      | 20                  |                                                                |
| Bn256AddGas             | 150                 | Thực hiện hoạt động đường cong elliptic Bn256                  |
| Bn256ScalarMulGas       | 6000                |                                                                |
| Bn256PairingBaseGas     | 45000               |                                                                |
| Bn256PairingPerPointGas | 34000               |                                                                |
| VMLogBaseGas            | 100                 | Ghi bản ghi vào tập tin bản ghi của nút - chỉ dành cho Klaytn  |
| VMLogPerByteGas         | 20                  | Chỉ dành cho Klaytn                                            |
| FeePayerGas             | 300                 | Nhận địa chỉ của feePayer - chỉ dành cho Klaytn                |
| ValidateSenderGas       | 5000 cho mỗi chữ ký | Xác thực địa chỉ và chữ ký của người gửi - chỉ dành cho Klaytn |

Tổng lượng gas của các mục có XXXBaseGas và XXXPerWordGas (ví dụ: Sha256BaseGas, Sha256PerWordGas) được tính như sau

```
TotalGas = XXXBaseGas + (số từ * XXXPerWordGas)
```

IntrinsicGasCost = KeyCreationGas + KeyValidationGas + PayloadGas + TxTypedGas

```
* `PayloadGas` is calculated based on the size of the data field in the tx.
* `KeyCreationGas` is calculated when the transaction registers new keys. Only applicable in `accountUpdate` transaction.
* `KeyValidationGas` is calculated based on the number of signatures.
* `TxTypedGas` is defined based on the transaction types.

Before we get into the detail, keep in mind that not all key types apply the keyGases (`KeyCreationGas` and `KeyValidationGas`).

| Key Type  | Are those keyGases applicable?     |
|:--------- |:---------------------------------- |
| Nil       | No                                 |
| Legacy    | No                                 |
| Fail      | No                                 |
| Public    | Yes                                |
| MultiSig  | Yes                                |
| RoleBased | Depending on key types in the role |

### KeyCreationGas <a id="keyCreationGas"></a>
The KeyCreationGas is calculated as `(number of registering keys) x TxAccountCreationGasPerKey (20000)`. </br>Please Keep in mind that Public key type always has only one registering key, so the gas would be always 20000.

### KeyValidationGas <a id="keyValidationGas"></a>
The KeyValidationGas is calculated as `(number of signatures - 1) x TxValidationGasPerKey(15000)`. </br>Please keep in mind that Public key type always has only one signature key, so the gas would be always zero.

A Klaytn transaction can also have a feePayer, so the total KeyValidationGas is like this.
```

### Bảng gas liên quan đến tài khoản <a href="#account-related-gas-table" id="account-related-gas-table"></a>

| Mục                        | Gas   | Mô tả                                                            |
| -------------------------- | ----- | ---------------------------------------------------------------- |
| TxAccountCreationGasPerKey | 20000 | Lượng gas cần thiết để tạo một cặp khóa                          |
| TxValidationGasPerKey      | 15000 | Lượng gas cần thiết để xác thực khóa                             |
| TxGasAccountUpdate         | 21000 | Lượng gas cần thiết để cập nhật một tài khoản                    |
| TxGasFeeDelegated          | 10000 | Lượng gas cần thiết cho một lượt ủy thác phí                     |
| TxGasFeeDelegatedWithRatio | 15000 | Lượng gas cần thiết để ủy thác phí kèm tỷ lệ                     |
| TxGasCancel                | 21000 | Lượng gas cần thiết để hủy một giao dịch có cùng số dùng một lần |
| TxGasValueTransfer         | 21000 | Lượng gas cần thiết để chuyển KLAY                               |
| TxGasContractExecution     | 21000 | Lượng gas cơ sở để thực thi hợp đồng                             |
| TxDataGas                  | 100   | Lượng gas cần cho mỗi byte đơn lẻ của giao dịch                  |

Lượng gas cần cho dữ liệu tải tin được tính toán như dưới đây

```
GasPayload = number_of_bytes * TxDataGas
```

### PayloadGas <a href="#payloadgas" id="payloadgas"></a>

Calculating `PayloadGas` is simple. It is calculated as `(number_of_bytes_of_tx_input) x TxDataGas(100)`

### TxTypedGas <a href="#txtypedgas" id="txtypedgas"></a>

There are three types of transactions in klaytn; `base`, `feeDelegated`, and `feeDelegatedWithFeeRatio`.

For example,

* TxTypeValueTransfer is the `base` type of the valueTransaction transaction.
* TxTypeFeeDelegatedValueTransfer is a `feeDelegated` type of the valueTransfer transaction.
* TxTypeFeeDelegatedValueTransferWithRatio is a `feeDelegatedWithRatio` type of the valueTransfer transaction.

This is important when calculating TxTypedGas:

* First, check the TxType is `feeDelegated` or `feeDelegatedWithFeeRatio`.
  * If the TxType is `feeDelegated`, add `TxGasFeeDelegated(10000)` to TxTypedGas
  * If the TxType is `feeDelegatedWithFeeRatio`, add `TxGasFeeDelegatedWithRatio (15000)` to TxTypedGas
* Second, check the transaction creates contract or not.
  * If the transaction creates contract, add `TxGasContractCreation (53000)` to TxTypedGas.
  * Otherwise, add `TxGas (21000)` to TxTypedGas.

For example,

* If it's legacyTransaction and creates contract, the TxTypedGas would be `0 + TxGasContractCreation(53000)`.
* If it's TxTypeFeeDelegatedValueTransfer, the TxTypedGas would be `TxGasFeeDelegated(10000) + TxGas (21000)`
* If it's TxTypeFeeDelegatedSmartContractDeployWithRatio, the TxTypedGas would be `TxGasFeeDelegatedWithRatio (15000) + TxGasContractCreation (53000)`


# Phí giao dịch (Các tài liệu trước)

{% hint style="success" %}
NOTE: This document contains the transaction fee used before the activation of the protocol upgrade. If you want the latest document, please refer to [latest document](/content/klaytn/design/transaction-fees).
{% endhint %}

The transaction fee of one transaction is calculated as follows:

```
Transaction fee := (Gas used) x (GasPrice)
```

As an easy-to-understand analogy in this regard, suppose you're filling up gas at a gas station. The gas price is determined by the refinery every day, and today's price is $2. If you fill 15L up, then you would pay $30 = 15L x $2/1L for it, and the $30 will be paid out of your bank account. Also, the transaction will be recorded in the account book.

Transaction fee works just the same as above. The network determines the gas price for every block. Suppose the gas price for the current block is 30 ston. If a transaction submitted by `from` account was charged 21000 gas, then 630000 ston = (21000 gas \* 30 ston) would be paid out of the `from` account. Also, the transaction will be recorded in the block, and it will be applied in the state of all blockchain nodes.

Summing it up again, this calculated transaction fee is subtracted from the sender's or fee payer's account. However, the fee can be deducted from the balance only if the transaction is created by klay\_sendTransaction/eth\_sendTransaction. Because the other transactions cannot change the state since they cannot be included in the block. They are just a simulation in some way.

This is an overall explanation of the transaction fee, and from this point, we would give a detailed explanation of how gas price is determined and how the gas is calculated.

## Unit Price Overview <a href="#unit-price-overview" id="unit-price-overview"></a>

Mọi hành động làm thay đổi trạng thái của chuỗi khối đều cần đến gas. Khi một nút xử lý giao dịch của người dùng, ví dụ như gửi KLAY, dùng token ERC-20, hoặc thực thi một hợp đồng, người dùng phải trả phí cho việc tính toán và sử dụng dung lượng lưu trữ. Số tiền thanh toán được xác định bằng số `gas` cần dùng.

In Ethereum, users set the gas price for each transaction, and miners choose which transactions to be included in their block to maximize their reward. It is something like bidding for limited resources. This approach has been working because it is market-based. However, the transaction cost fluctuates and often becomes too high to guarantee the execution.

To solve the problem, Klaytn is using a fixed unit price and the price can be adjusted by the governance council. This policy ensures that every transaction will be handled equally and be guaranteed to be executed. Therefore, users do not need to struggle to determine the right unit price.

### Transaction Validation against Unit Price <a href="#transaction-validation-against-unit-price" id="transaction-validation-against-unit-price"></a>

Klaytn only accepts transactions with gas prices, which can be set by the user, that are equal to the unit price of Klaytn; it rejects transactions with gas prices that are different from the unit price in Klaytn.

### Unit Price Error <a href="#unit-price-error" id="unit-price-error"></a>

The error message `invalid unit price` is returned when the gas price of a transaction is not equal to the unit price of Klaytn.

### Thay thế giao dịch <a href="#transaction-replacement" id="transaction-replacement"></a>

Klaytn hiện không cung cấp phương pháp thay thế giao dịch bằng đơn giá, nhưng có thể hỗ trợ các phương pháp thay thế giao dịch khác trong tương lai. Xin lưu ý rằng trong Ethereum, một giao dịch với một số dùng một lần nhất định có thể được thay thế bằng một giao dịch mới với giá gas cao hơn.

## Biểu giá gas của Klaytn <a href="#klaytns-gas-table" id="klaytns-gas-table"></a>

Về cơ bản, Klaytn luôn duy trì khả năng tương thích với Ethereum. Vì thế, biểu giá gas của Klaytn cũng khá tương đồng với biểu giá của Ethereum. Tuy nhiên, do sự tồn tại của những tính năng độc đáo của Klaytn nên sẽ có một số hằng số mới cho những tính năng đó.

{% hint style="success" %}
LƯU Ý: Tài liệu này chứa biểu giá gas được sử dụng trước khi kích hoạt nâng cấp giao thức. Nếu bạn muốn nhận tài liệu mới nhất, vui lòng tham khảo [tài liệu mới nhất](/content/klaytn/design/transaction-fees).
{% endhint %}

Coming back to `IntrinsicGas`, a transaction's `intrinsicGas` can be calculated by adding up the next four factors.

```
IntrinsicGasCost = KeyCreationGas + KeyValidationGas + PayloadGas + TxTypedGas
```

* `PayloadGas` is calculated based on the size of the data field in the tx.
* `KeyCreationGas` is calculated when the transaction registers new keys. Only applicable in `accountUpdate` transaction.
* `KeyValidationGas` is calculated based on the number of signatures.
* `TxTypedGas` is defined based on the transaction types.

| Mục             | Gas   | Mô tả                                                                                                              |
| --------------- | ----- | ------------------------------------------------------------------------------------------------------------------ |
| G\_zero         | 0     | Không cần thanh toán cho các hoạt động của bộ Wzero                                                                |
| G\_base         | 2     | Lượng gas phải trả cho các hoạt động của bộ Wbase                                                                  |
| G\_verylow      | 3     | Lượng gas phải trả cho các hoạt động của bộ Wverylow                                                               |
| G\_low          | 5     | Lượng gas phải trả cho các hoạt động của bộ Wlow                                                                   |
| G\_mid          | 8     | Lượng gas phải trả cho các hoạt động của bộ Wmid                                                                   |
| G\_high         | 10    | Lượng gas phải trả cho các hoạt động của bộ Whigh                                                                  |
| G\_blockhash    | 20    | Khoản thanh toán cho hoạt động BLOCKHASH                                                                           |
| G\_extcode      | 700   | Lượng gas phải trả cho các hoạt động của bộ Wextcode                                                               |
| G\_balance      | 400   | Lượng gas phải trả cho một hoạt động BALANCE                                                                       |
| G\_sload        | 200   | Được trả cho một hoạt động SLOAD                                                                                   |
| G\_jumpdest     | 1     | Được trả cho một hoạt động JUMPDEST                                                                                |
| G\_sset         | 20000 | Được trả cho một hoạt động SSTORE khi giá trị lưu trữ được đặt từ số 0 sang số khác 0                              |
| G\_sreset       | 5000  | Được trả cho một hoạt động SSTORE khi giá trị bằng không của giá trị không đổi, hoặc được đặt thành số 0           |
| G\_sclear       | 15000 | Khoản hoàn tiền đã thực hiện (được thêm vào bộ đếm hoàn tiền) khi giá trị lưu trữ được đặt từ số khác 0 thành số 0 |
| R\_selfdestruct | 24000 | Khoản hoàn tiền đã thực hiện (được thêm vào bộ đếm hoàn tiền) cho việc tự hủy một tài khoản                        |
| G\_selfdestruct | 5000  | Lượng gas phải trả cho một hoạt động SELFDESTRUCT                                                                  |
| G\_create       | 32000 | Được trả cho một hoạt động CREATE                                                                                  |
| G\_codedeposit  | 200   | Được trả theo byte cho hoạt động CREATE để thành công trong việc đặt mã vào trạng thái                             |
| G\_call         | 700   | Được trả cho một hoạt động CALL                                                                                    |
| G\_callvalue    | 9000  | Được trả cho một giao dịch chuyển giá trị khác 0 như một phần của hoạt động CALL                                   |
| G\_callstipend  | 2300  | Khoản trợ cấp cho hợp đồng được gọi ra, được trừ khỏi Gcallvalue đối với giao dịch chuyển giá trị khác 0           |
| G\_newtài khoản | 25000 | Được trả cho hoạt động CALL hoặc SELFDESTRUCT để tạo tài khoản                                                     |
| G\_exp          | 10    | Khoản thanh toán một phần cho hoạt động EXP                                                                        |
| G\_expbyte      | 50    | Khoản thanh toán một phần khi nhân với dlog256(exponent)e cho hoạt động EXP                                        |
| G\_memory       | 3     | Được trả cho mỗi một từ bổ sung khi mở rộng bộ nhớ                                                                 |
| G\_txcreate     | 32000 | Được trả bởi tất cả các giao dịch tạo hợp đồng                                                                     |
| G\_transaction  | 21000 | Được trả cho mọi giao dịch                                                                                         |
| G\_log          | 375   | Khoản thanh toán một phần cho hoạt động LOG                                                                        |
| G\_logdata      | 8     | Được trả cho mỗi byte trong dữ liệu của hoạt động LOG                                                              |
| G\_logtopic     | 375   | Được trả cho từng chủ đề của hoạt động LOG                                                                         |
| G\_sha3         | 30    | Được trả cho mỗi hoạt động SHA3                                                                                    |
| G\_sha3word     | 6     | Được trả cho từng từ (được làm tròn) cho dữ liệu nhập vào hoạt động SHA3                                           |
| G\_copy         | 3     | Thanh toán một phần cho các hoạt động \*COPY, nhân lên theo số từ được sao chép, được làm tròn                     |
| G\_blockhash    | 20    | Khoản thanh toán cho hoạt động BLOCKHASH                                                                           |
| G\_extcodehash  | 400   | Được trả cho việc nhận hàm băm keccak256 của mã hợp đồng                                                           |
| G\_create2      | 32000 | Được trả cho mã vận hành CREATE2, hoạt động giống hệt như CREATE nhưng dùng những đối số khác                      |

| Key Type  | Are those keyGases applicable?     |
| --------- | ---------------------------------- |
| Nil       | No                                 |
| Legacy    | No                                 |
| Fail      | No                                 |
| Public    | Yes                                |
| MultiSig  | Yes                                |
| RoleBased | Depending on key types in the role |

Hợp đồng đã lập trước là loại hợp đồng đặc biệt, thường thực hiện các phép tính toán mã hóa phức tạp và được khởi tạo bởi những hợp đồng khác.

| Mục                     | Gas                 | Mô tả                                                          |
| ----------------------- | ------------------- | -------------------------------------------------------------- |
| EcrecoverGas            | 3000                | Thực hiện hoạt động ECRecover                                  |
| Sha256BaseGas           | 60                  | Thực hiện hoạt động hàm băm sha256                             |
| Sha256PerWordGas        | 12                  |                                                                |
| Ripemd160BaseGas        | 600                 | Thực hiện hoạt động Ripemd160                                  |
| Ripemd160PerWordGas     | 120                 |                                                                |
| IdentityBaseGas         | 15                  |                                                                |
| IdentityPerWordGas      | 3                   |                                                                |
| ModExpQuadCoeffDiv      | 20                  |                                                                |
| Bn256AddGas             | 500                 | Thực hiện hoạt động đường cong elliptic Bn256                  |
| Bn256ScalarMulGas       | 40000               |                                                                |
| Bn256PairingBaseGas     | 100000              |                                                                |
| Bn256PairingPerPointGas | 80000               |                                                                |
| VMLogBaseGas            | 100                 | Ghi bản ghi vào tập tin bản ghi của nút - chỉ dành cho Klaytn  |
| VMLogPerByteGas         | 20                  | Chỉ dành cho Klaytn                                            |
| FeePayerGas             | 300                 | Nhận địa chỉ của feePayer - chỉ dành cho Klaytn                |
| ValidateSenderGas       | 5000 cho mỗi chữ ký | Xác thực địa chỉ và chữ ký của người gửi - chỉ dành cho Klaytn |

A Klaytn transaction can also have a feePayer, so the total KeyValidationGas is like this.

```
KeyValidationGas =  (KeyValidationGas for a sender) + (KeyValidationGas for a feePayer)
```

### PayloadGas <a href="#payloadgas" id="payloadgas"></a>

`PayloadGas` is calculated as below.

````
# legacy-typed transaction
PayloadGas = number_of_zero_bytes x TxDataZeroGas (4) + number_of_nonzero_bytes x TxDataNonZeroGas (68)`

### Bảng gas liên quan đến tài khoản <a id="account-related-gas-table"></a>

| Mục                        | Gas   | Mô tả                                                            |
|:-------------------------- |:----- |:---------------------------------------------------------------- |
| TxAccountCreationGasPerKey | 20000 | Lượng gas cần thiết để tạo một cặp khóa                          |
| TxValidationGasPerKey      | 15000 | Lượng gas cần thiết để xác thực khóa                             |
| TxGasAccountUpdate         | 21000 | Lượng gas cần thiết để cập nhật một tài khoản                    |
| TxGasFeeDelegated          | 10000 | Lượng gas cần thiết cho một lượt ủy thác phí                     |
| TxGasFeeDelegatedWithRatio | 15000 | Lượng gas cần thiết để ủy thác phí kèm tỷ lệ                     |
| TxGasCancel                | 21000 | Lượng gas cần thiết để hủy một giao dịch có cùng số dùng một lần |
| TxGasValueTransfer         | 21000 | Lượng gas cần thiết để chuyển KLAY                               |
| TxGasContractExecution     | 21000 | Lượng gas cơ sở để thực thi hợp đồng                             |
| TxDataGas                  | 100   | Lượng gas cần cho mỗi byte đơn lẻ của giao dịch                  |

Lượng gas cần cho dữ liệu tải tin được tính toán như dưới đây

```text
GasPayload = number_of_bytes * TxDataGas
````

### TxTypedGas <a href="#txtypedgas" id="txtypedgas"></a>

There are three types of transactions in klaytn; `base`, `feeDelegated`, and `feeDelegatedWithFeeRatio`.

For example,

* TxTypeValueTransfer is the `base` type of the valueTransaction transaction.
* TxTypeFeeDelegatedValueTransfer is a `feeDelegated` type of the valueTransfer transaction.
* TxTypeFeeDelegatedValueTransferWithRatio is a `feeDelegatedWithRatio` type of the valueTransfer transaction.

This is important when calculating TxTypedGas:

* First, check the TxType is `feeDelegated` or `feeDelegatedWithFeeRatio`.
  * If the TxType is `feeDelegated`, add `TxGasFeeDelegated(10000)` to TxTypedGas
  * If the TxType is `feeDelegatedWithFeeRatio`, add `TxGasFeeDelegatedWithRatio (15000)` to TxTypedGas
* Second, check the transaction creates contract or not.
  * If the transaction creates contract, add `TxGasContractCreation (53000)` to TxTypedGas.
  * Otherwise, add `TxGas (21000)` to TxTypedGas.

For example,

* If it's legacyTransaction and creates contract, the TxTypedGas would be `0 + TxGasContractCreation(53000)`.
* If it's TxTypeFeeDelegatedValueTransfer, the TxTypedGas would be `TxGasFeeDelegated(10000) + TxGas (21000)`
* If it's TxTypeFeeDelegatedSmartContractDeployWithRatio, the TxTypedGas would be `TxGasFeeDelegatedWithRatio (15000) + TxGasContractCreation (53000)`

| Loại khóa | Gas                                                                                                                                                                                                                 |
| --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Nil       | Không có                                                                                                                                                                                                            |
| Legacy    | 0                                                                                                                                                                                                                   |
| Fail      | 0                                                                                                                                                                                                                   |
| Public    | GasCreationPerKey (20000)                                                                                                                                                                                           |
| MultiSig  | (khóa) \* GasCreationPerKey                                                                                                                                                                                         |
| RoleBased | Phí gas được tính toán dựa trên các khóa trong từng vai trò. ví dụ: GasRoleTransaction = (khóa) *GasCreationPerKey* *GasRoleAccountUpdate = (khóa)* GasCreationPerKey GasRoleFeePayer = (khóa) \* GasCreationPerKey |


# Đồng tiền mặc định của Klaytn - KLAY

## KLAY <a href="#klay" id="klay"></a>

KLAY là loại tiền kỹ thuật số chính và có thể chuyển nhượng nội bộ của Klaytn và được dùng để thanh toán phí giao dịch khi tạo hoặc thực thi hợp đồng thông minh, hoặc khi chuyển khoản KLAY.

KLAY là một phần tử cần thiết – một dạng nhiên liệu – để vận hành nền tảng ứng dụng phân tán Klaytn. Đây là một hình thức thanh toán được khách hàng của nền tảng sử dụng để thanh toán cho các nút đồng thuận (CN) thực thi các hoạt động được yêu cầu. To put it another way, KLAY is an incentive; it ensures that developers write high-quality applications (wasteful code costs more) and that the network remains healthy (CNs are compensated for the resources they contribute).

## Các đơn vị của KLAY <a href="#units-of-klay" id="units-of-klay"></a>

Klaytn sử dụng hệ thống đơn vị sau cho KLAY.

* `peb` là đơn vị tiền tệ nhỏ nhất.
* `ston` là một tên cho `Gpeb` và được giới thiệu vì tính thuận tiện.
* Một `KLAY` bằng 10^18 peb.

| Đơn vị | giá trị peb | peb                                       |
| ------ | ----------- | ----------------------------------------- |
| peb    | 1 peb       | 1                                         |
| kpeb   | 10^3 peb    | 1.000                                     |
| Mpeb   | 10^6 peb    | 1.000.000                                 |
| Gpeb   | 10^9 peb    | 1.000.000.000                             |
| ston   | 10^9 peb    | 1.000.000.000                             |
| uKLAY  | 10^12 peb   | 1.000.000.000.000                         |
| mKLAY  | 10^15 peb   | 1.000.000.000.000.000                     |
| KLAY   | 10^18 peb   | 1.000.000.000.000.000.000                 |
| kKLAY  | 10^21 peb   | 1.000.000.000.000.000.000.000             |
| MKLAY  | 10^24 peb   | 1.000.000.000.000.000.000.000.000         |
| GKLAY  | 10^27 peb   | 1.000.000.000.000.000.000.000.000.000     |
| TKLAY  | 10^30 peb   | 1.000.000.000.000.000.000.000.000.000.000 |

#### Các API liên quan đến Đơn vị KLAY <a href="#apis-related-to-klay-units" id="apis-related-to-klay-units"></a>

`klay.toPeb` và `klay.fromPeb` là các API thuận tiện để chuyển đổi giữa các đơn vị KLAY.

```
$ ./klay attach data/dd/klay.ipc
...
> klay.fromPeb(25, "peb")
"25"
> klay.fromPeb(25, "Gpeb")
"0.000000025"
> klay.fromPeb(25, "ston")
"0.000000025"
> klay.fromPeb(25, "KLAY")
"0.000000000000000025"
> klay.toPeb(25, "peb")
"25"
> klay.toPeb(25, "ston")
"25000000000"
> klay.toPeb(25, "KLAY")
"25000000000000000000"
```

Bạn có thể nhận danh sách tất cả các đơn vị được hỗ trợ bởi `klay.toPeb` và `klay.fromPeb` bằng cách gửi một chuỗi đơn vị không hợp lệ, ví dụ như chuỗi dưới đây.

```
> klay.toPeb(1, "something-does-not-exist")
Error: This unit doesn't exist, please use one of the following units
"noKLAY": "0"
"peb": "1"
"kpeb": "1000"
"Mpeb": "1000000"
"Gpeb": "1000000000"
"ston": "1000000000"
"uKLAY": "1000000000000"
"mKLAY": "1000000000000000"
"KLAY": "1000000000000000000"
"kKLAY": "1000000000000000000000"
"MKLAY": "1000000000000000000000000"
"GKLAY": "1000000000000000000000000000"
"TKLAY": "1000000000000000000000000000000"

    at web3.js:2170:19
    at web3.js:2255:49
    at <anonymous>:1:1
```


# Nền kinh tế token

## Tổng quan <a href="#overview" id="overview"></a>

Nền kinh tế token của Klaytn được thiết kế để tạo ra các cấu trúc cấp vốn bền vững để trao quyền cho hệ sinh thái của mình, các sáng kiến tăng trường và các khoản đầu tư chiến lược. Nhiều dự án chuỗi khối công khai có hệ thống tiền tệ chỉ khuyến khích riêng những người vận hành nút của họ (thợ đào hoặc người tạo khối), chỉ tập trung vào khía cạnh kỹ thuật hoặc bảo trì mạng lưới. Tuy nhiên, những thiết kế như vậy lại bỏ qua tầm quan trọng của việc khuyến khích những nhóm người tham gia khác cũng đóng góp cho sự tăng trưởng của nền kinh tế token của mạng lưới, hoặc đầu tư vào các triển vọng tăng trưởng dài hạn. Ngược lại, nền kinh tế token của Klaytn lại được thiết kế để bù đắp cho các hình thức đóng góp đa dạng đến từ nhiều người tham gia và ngoài việc duy trì các nút chuỗi khối của mình, chúng tôi còn có một cấu trúc tài trợ được tích hợp sẵn để tận dụng các nguồn lực bền vững, nhằm thúc đẩy các sáng kiến về tăng trưởng trong tương lai và các dự án đầu tư được lấy nguồn một cách chiến lược.

## Cấu trúc cấp vốn <a href="#funding-structure" id="funding-structure"></a>

Cấu trúc cấp vốn của Klaytn chạy liên tục với việc tạo khối của mạng lưới Klaytn. Với mỗi khối mới, KLAY mới được phát hành và tổng phí giao dịch được dùng trong khối (được gọi chung là “phần thưởng khối”) được tổng hợp và phân phối cho ba toài khoản đích sau theo tỷ lệ được xác định trước:

* Klaytn Governance Council (GC) Reward:
  * GC Block Proposer Reward: 10%
  * GC Staking Award: 40%
* Klaytn Community Fund (KCF): 30%
* Klaytn Foundation Fund (KFF): 20%

6,4 KLAY sẽ được tạo cho mỗi khối mới. Điều này ngụ ý rằng khoảng 200 triệu KLAY sẽ được tạo mỗi năm, tương đương với 2% lạm phát hàng năm so với 10 tỷ KLAY được phát hành vào thời điểm khởi nguyên (tỷ lệ lạm phát hàng năm có thể thay đổi thông qua Quy trình quản trị của Klaytn). Phí giao dịch được tính theo mỗi OPCODE và được tính theo biểu phí giao dịch. Để biết thông tin chi tiết về biểu phí giao dịch, vui lòng tham khảo phần [Phí giao dịch](/content/klaytn/design/transaction-fees).

## Phần thưởng cho Hội đồng quản trị của Klaytn <a href="#klaytn-governance-council-reward" id="klaytn-governance-council-reward"></a>

Hội đồng quản trị của Klaytn là nhóm tập thể các Người vận hành Core Cell (CCO). Các thành viên hội đồng có trách nhiệm duy trì Core Cell (CC), việc này giúp Hội đồng trở thành cơ quan thiết yếu trong hệ sinh thái Klaytn chịu trách nhiệm cung cấp cơ sở hạ tầng cơ sở. Để trở thành thành viên Hội đồng, ứng viên phải trải qua quá trình đánh giá trình độ theo Quy trình quản trị của Klaytn và phải nắm giữ ít nhất 5 triệu KLAY. Phần thưởng của Hội đồng quản trị của Klaytn là một cấu trúc dùng để khuyến khích các thành viên Hội đồng tiếp tục cung cấp nền tảng ổn định cho hệ sinh thái Klaytn.

### Cơ chế phần thưởng cho Hội đồng quản trị của Klaytn <a href="#klaytn-governance-council-reward-mechanism" id="klaytn-governance-council-reward-mechanism"></a>

Đối với mỗi khối, một Ủy ban sẽ được thành lập, bao gồm các thành viên Hội đồng được lựa chọn ngẫu nhiên. Mỗi Ủy ban có một thành viên được giao vai trò là Người đề xuất; tất cả các thành viên khác của Ủy ban sẽ đảm nhận vai trò là Người xác thực. Khi một khối được tạo thành công và được thêm vào chuỗi khối Klaytn, Người đề xuất của khối đó sẽ được thưởng 100% phần thưởng khối. Xác suất thành viên hội đồng được chọn là Người đề xuất tỷ lệ thuận với số lượng KLAY mà thành viên đó nắm giữ; nghĩa là một thành viên nắm giữ càng nhiều KLAY thì càng có nhiều khả năng người đó sẽ được chọn làm Người đề xuất và có khả năng nhận được phần thưởng khối.

Miễn đáp ứng được yêu cầu về mức nắm giữ tối thiểu là 5 triệu KLAY, các thành viên Hội đồng quản trị KLAY có thể tự do nắm giữ hoặc hủy nắm giữ KLAY của mình. Thông tin nắm giữ sẽ được cập nhật sau mỗi 86.400 khối và KLAY mới được nắm giữ sẽ có hiệu lực sau hai chu kỳ cập nhật kể từ thời điểm hoàn tất quá trình nắm giữ. Việc rút phần KLAY đã nắm giữ cần đến một tuần chờ đợi để ngăn chặn việc các thành viên ác ý rút lui ngay lập tức.

Để ngăn chặn tình trạng các nhóm nhỏ gồm các thành viên Hội đồng có mức đầu tư cao độc quyền nhận phần thưởng cho Hội đồng quản trị của Klaytn, hệ số Gini có thể được sử dụng để điều chỉnh số tiền KLAY thực tế được nắm giữ. Công thức áp dụng như sau, trong đó G là viết tắt của hệ số Gini trong việc phân phối phần KLAY được nắm giữ của Hội đồng quản trị:

* *Số lượng nắm giữ đã điều chỉnh = (Số lượng nắm giữ của thành viên hội đồng quản trị)^(1/1+G)*

### Hình phạt cho các Thành viên hội đồng có hành vi sai trái <a href="#penalty-for-misbehaving-council-members" id="penalty-for-misbehaving-council-members"></a>

Thành viên hội đồng có thể bị phạt nếu thực hiện các hành vi sai trái theo định nghĩa dưới đây. Trong tương lai, nhiều quy tắc phạt hơn có thể sẽ được thiết lập và hoàn thiện thông qua Quy trình quản trị của Klaytn.

Gây ra lỗi về an toàn:

* Một thành viên hội đồng được chọn làm Người đề xuất không được tạo ra nhiều hơn một khối với cùng một số khối
* Một thành viên hội đồng được chọn làm Người đề xuất không được bỏ qua các giao dịch nhất định một cách có chủ ý

Gây ra lỗi về xác định thực thể sống:

* Một thành viên hội đồng được chọn làm Người đề xuất phải tạo ra một khối hợp lệ
* Một thành viên hội đồng được chọn làm Người xác thực phải xác thực nút được đề xuất bởi Người đề xuất

## Klaytn Community Fund <a href="#klaytn-community-fund" id="klaytn-community-fund"></a>

The Klaytn Community Fund (KCF) was established to support Klaytn's mission of enabling greater transparency and verifiability. It's important to keep in mind that the former Klaytn Growth Fund (KGF) and Klaytn Improvement Reserve (KIR) have merged to become the new Klaytn Community Fund (KCF).

The Klaytn Community Fund will be used to fund activities that improves the Klaytn ecosystem, such as:

1. **Rewarding Proof of Contribution**: The KCF will provide follow-up support, such as gas fee support to projects that have made significant on-chain contributions to the Klaytn ecosystem among services that have already been developed.
2. **Building our Developer Community**: The KCF will support various initiatives including hackathons, development education programs, collaborative research with the industry, and collaboration with various DAOs to foster and grow the Klaytn developer community.
3. **Fostering Ecosystem Services and Infrastructure**: The KCF will support essential ecosystem infrastructure, alongside the development of services with clear utility and provide marketing support.
4. **Klaytn Eco Fund Indirect Investment**: The KCF will make indirect mid-to long-term investments by entrusting specialized crypto VCs, and most of the profits generated upon subsequent investment recovery will be returned to the Klaytn ecosystem.

The administration of the Klaytn Community Fund follows a process in which the GC reviews and approves the use of funds in public forums on [Klaytn Square](https://square.klaytn.foundation/Home). The Foundation will submit a budget proposal for each category to the GC for approval. Within the approved budget, each specific use will be reviewed and approved again by the GC. In the meantime, the KCF is currently being run as a [pilot program](https://klaytn.foundation/kcf-grant-pilot/) and interested parties can visit the [Klaytn Governance Forum](https://govforum.klaytn.foundation/t/operational-procedures-of-the-kcf-grant-program-pilot/288) for more details about the program.

### Khái niệm chung

Quỹ tăng trưởng của Klaytn (KGF) nhắm đến việc giúp nền kinh tế Klaytn tăng trưởng bằng cách cung cấp các khoản tài trợ và đầu tư vào các tổ chức và cá nhân có đóng góp cho nền kinh tế Klaytn. Công nghệ của Klaytn mang đến những cơ hội to lớn để mọi người có thể lưu trữ, chuyển giao và trao đổi dữ liệu và giá trị trên toàn cầu một cách dễ dàng với chi phí tối thiểu. Và vì đây là một mạng lưới mở, ai cũng có thể tham gia để xây dựng một ứng dụng mà không cần xin phép. Tuy nhiên, việc áp dụng chuỗi khối rộng rãi hơn đã bị cản trở do công nghệ này vẫn còn đang ở giai đoạn đầu và hầu hết các giá trị và dữ liệu vẫn đang được quản lý theo cách truyền thống dưới dạng hợp đồng pháp lý, lưu trữ cục bộ, v.v. Và KGF được dùng với mục đích giải quyết các vấn đề này. KGF sẽ hỗ trợ các chương trình khác nhau nhằm thúc đẩy việc áp dụng Klaytn trên khắp các ngành, ví dụ như tặng thưởng cho những người đưa ra bằng chứng đóng góp trên chuỗi và đầu tư vào các dApp giai đoạn đầu. Quỹ này sẽ liên tục được tài trợ thông qua một tỷ lệ phần thưởng khối nhất định (tham khảo [Cấu trúc cấp vốn](#funding-structure)).

Klaytn Foundation Fund (KFF) is an operational fund that will focus on this two main categories:

1. **Ecosystem Support**: This includes providing minor financial assistance, securing new GC members, liquidity provisions, and developing / funding services led by the Foundation.
2. **Foundation Operations**: This includes operating expenses such as development, accounting, infrastructure operations, marketing, and labor, as well as financial management and investment attraction costs.

Khi công nghệ tiếp tục được cải tiến và nhu cầu của người dùng thay đổi theo thời gian, nền tảng của chúng tôi phải có khả năng thích ứng nhanh chóng với mọi tình huống mới phát sinh. Để đáp ứng những thay đổi như vậy, chúng tôi không chỉ phải cải thiện dịch vụ mà còn phải thực hiện nhiều hoạt động khác nhau để duy trì hệ sinh thái của Klaytn. Ví dụ, việc nghiên cứu và phát triển để có được công nghệ tốt hơn, hoặc các dự án đóng góp vào sự phát triển chung của hệ sinh thái có thể là một phần của các hoạt động này. Các hoạt động này là rất cần thiết để Klaytn có thể phát triển không ngừng. Khoản dự trữ cải tiến của Klaytn (KIR) sẽ được triển khai cho các hoạt động cải thiện hệ sinh thái của Klaytn, ví dụ như:

| Danh mục                           | Chi tiết                                                                                                                                          |
| ---------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Phát triển**                     | <ul><li>IDE & Các trình biên tập</li><li>Oracle</li><li>Thư viện hợp đồng</li></ul>                                                               |
| **Cơ sở hạ tầng**                  | <ul><li>Mạng thử nghiệm cục bộ</li><li>Hệ thống tập tin phi tập trung</li><li>Đa VM</li></ul>                                                     |
| **Thử nghiệm, Gỡ lỗi, Triển khai** | <ul><li>Các công cụ thử nghiệm & triển khai</li><li>Các công cụ kiểm toán & bảo mật</li></ul>                                                     |
| **Giám sát & Phân tích**           | <ul><li>Giám sát</li><li>Phân tích</li></ul>                                                                                                      |
| **Giáo dục & Hoạt động**           | <ul><li>Tài liệu</li><li>Tài liệu đào tạo</li><li>Xây dựng cộng đồng</li><li>Hoạt động nguồn mở (bao gồm hoạt động săn lỗi nhận thưởng)</li></ul> |
| **Nghiên cứu**                     | <ul><li>Bảo mật, khả năng mở rộng, mã hóa, v.v.</li></ul>                                                                                         |

Các đề xuất KIR có thể được tạo ra bởi bất kỳ người tham gia nào trong hệ sinh thái Klaytn. Các đề xuất chi tiêu KIR sẽ được xử lý theo Quy trình quản trị KIR. Tham khảo phần [Quy trình đánh giá Khoản dự trữ cải tiến của Klaytn](/content/klaytn/design/governance#klaytn-improvement-reserve-review-process) để biết thêm thông tin về thủ tục này. Khi một đề xuất chi tiêu đã được thông qua, KLAY sẽ được phân phối định kỳ, từ tổng số tiền được xác định trước, dựa trên mức tiến độ của dự án. Quy trình này có thể thay đổi dựa theo quy mô của dự án, tuy nhiên theo kế hoạch, quy trình này sẽ diễn ra hàng tháng.

Để biết thêm thông tin, hãy truy cập [Diễn đàn Khoản dự trữ cải tiến của Klaytn](https://kir.klaytn.foundation/).


# Quản trị

## Tổng quan <a href="#overview" id="overview"></a>

### Quản trị Klaytn: Bước đi đầu tiên đến với công nghệ phi tập trung <a href="#klaytn-governance-taking-the-first-step-to-decentralization" id="klaytn-governance-taking-the-first-step-to-decentralization"></a>

Hội đồng quản trị của Klaytn là một hội đồng có quyền quyết định về nhiều vấn đề quản trị khác nhau. Để bảo đảm cho độ tin cậy của Hội đồng, các thành viên ban đầu của Hội quản trị đã được giới hạn trong các tổ chức đáng tin cậy. Điều này được lựa chọn vì mục đích đảm bảo hiệu quả trong giai đoạn phát triển và ổn định của nền tảng. Klaytn đạt đến giai đoạn này bằng cách hợp tác với 31 thành viên Hội đồng quản trị và một cơ chế vận hành trơn tru của Mạng chính thức Klaytn.

Klaytn tin rằng việc quản trị Klaytn sẽ dẫn dắt sự tăng trưởng của Klaytn theo hướng phù hợp với sự chuyển mình của thế giới này. Một trong những sự chuyển đổi quan trọng của thế giới này đến từ sự phát triển của vũ trụ ảo. Những tiến bộ về công nghệ đang mở ra một thế giới được vũ trụ ảo hóa. Cụ thể, chúng ta đang chứng kiến tầm ảnh hưởng ngày càng lớn mạnh của các thực thể phi truyền thống, ví dụ như Tổ chức tự trị phi tập trung (DAO) và các nhà xây dựng. Là một tổ chức vận hành dựa trên hợp đồng thông minh mà không có cấu trúc tập trung, DAO sẽ là thực thể cốt lõi trong vũ trụ ảo. Các nhà xây dựng sẽ có nhiều ảnh hưởng hơn nhờ đóng góp vào quá trình vận hành và phát triển của vũ trụ ảo.

Chúng tôi đang sắp xếp lại cấu trúc quản trị của mình để có thể trở nên phù hợp hơn với một thế giới không ngừng thay đổi. Ngoài các doanh nghiệp truyền thống, Klaytn cũng bắt đầu cung cấp Tư cách thành viên của Hội đồng quản trị của Klaytn cho các thực thể phi truyền thống được đề cập ở trên.

Bằng cách giới thiệu một mô hình quản trị dựa trên cổ phần và loại bỏ Hệ số Gini khỏi cơ chế biểu quyết bình chọn của Klaytn, Klaytn cho phép những người tham gia vào hoạt động quản trị nhận thêm sự hỗ trợ từ Cộng đồng Klaytn nhằm định hình Klaytn phù hợp với mong muốn của họ. Các thực thể có thể đưa ra quyết định phù hợp trong một thế giới được vũ trụ ảo hóa sẽ có tầm ảnh hưởng lớn hơn tròng Klaytn GC. Chúng tôi tin rằng DAO và các nhà xây dựng sẽ dẫn dắt lĩnh vực này trong tương lai.

Khi cấp độ của quá trình vũ trụ ảo hóa vượt quá ngưỡng đến hạn, việc quản trị Klaytn sẽ được phân quyền hoàn toàn với nhiều loại thực thế khác nhau. Cuối cùng, Klaytn sẽ phát triển thành một DAO của các DAO và một nền tảng để các DAO truyền đạt tiếng nói của Cộng đồng Klaytn thông qua các cơ chế trên chuỗi.

## Các chủ đề về quản trị <a href="#governance-topics" id="governance-topics"></a>

Các chủ đề chính có thể được quyết định thông qua cấu trúc quản trị, bao gồm ba lĩnh vực sau đây và các đề xuất cần được thảo luận thêm để đưa ra quyết định có thể sẽ được giới thiệu trong một buổi họp định kỳ, hoặc một buổi họp tạm thời để đánh giá. Hội đồng quản trị của Klaytn phải đưa ra những quyết định có lợi nhất cho sự phát triển của Klaytn.

* **Công nghệ**
  * Những vấn đề liên quan đến cập nhật kỹ thuật của nền tảng. Đây là các vấn đề về cấu trúc cơ bản của chuỗi khối (ví dụ như Cấu trúc tài khoản), các tính năng mới (ví dụ như giải pháp L2) hoặc lịch trình cập nhật phần mềm.
* **Nền kinh tế**
  * Các vấn đề liên quan đến việc phát hành và cấu trúc phân phối KLAY, các thay đổi về phí giao dịch và phê duyệt chi tiêu cho Khoản dự trữ cải tiến của Klaytn, v.v. có trong danh mục này.
* **Quy tắc quản trị**
  * Các chủ thể và quy trình quản trị, cũng như các quy tắc về trách nhiệm và quyền hạn của các cơ quan quản lý, có trong danh mục này.

## Quy trình quản trị <a href="#governance-process" id="governance-process"></a>

Klaytn chủ yếu hướng đến quy trình quản trị diễn ra trong giao dịch (trên chuỗi). Thông qua quá trình này, phiếu bình chọn sẽ được ghi lại trên chuỗi khối và kết quả sẽ được áp dụng theo bình chọn. Khi nền tảng phát triển, sẽ có thêm nhiều vấn đề khác được xử lý thông qua quy trình quản trị trên chuỗi.

### Quy trình quản trị chung <a href="#general-governance-process" id="general-governance-process"></a>

Quy trình quản trị ban đầu được tiến hành theo trình tự sau: đưa ra đề xuất, các nhà cố vấn gửi tuyên bố quan điểm của mình, các thành viên hội đồng biểu quyết và nhiều thủ tục tiếp theo sẽ diễn ra tùy thuộc vào kết quả biểu quyết.

Những người có quyền đưa ra đề xuất có thể đảm bảo mỗi đề xuất đều được bình chọn thông qua việc đưa ra đề xuất đó. Khi đề xuất đã được đưa ra, những người cố vấn phải thực hiện phân tích chuyên môn cho đề xuất đó và gửi tuyên bố quan điểm kèm theo kết quả của họ.

Trong giai đoạn đầu của hoạt động quản trị Klaytn, các thành viên của Hội đồng quản trị của Klaytn sẽ có quyền biểu quyết bình chọn cho các đề xuất được đưa ra và họ sẽ tham khảo tuyên bố quan điểm của các nhà cố vấn đề bình chọn những đề xuất mà họ tin là lựa chọn tốt nhất. Nếu số phiếu bình chọn vượt qua ngưỡng, thì đề xuất sẽ được thông qua; ngược lại, đề xuất sẽ bị bác bỏ. Trong giai đoạn đầu, quy trình biểu quyết có thể được thay thế bằng quy trình thảo luận do quỹ Klaytn hỗ trợ điều phối. Các biện pháp tiếp theo đối với một đề xuất được phê duyệt sẽ được chủ tịch phụ trách và chủ tịch có trách nhiệm thực thi tất cả các đề xuất được hội đồng thông qua trong nhiệm kỳ của mình.

## Lộ trình quản trị <a href="#governance-roadmap" id="governance-roadmap"></a>

Các cơ quan tham gia vào hoạt động quản trị phải hành động vì lợi ích lâu dài của Klaytn thay vì chỉ chăm lo cho lợi ích cá nhân và họ phải tích cực tham gia vào quá trình quản trị. Ngoài ra, tất cả những người tham gia đóng góp vào mạng với tư cách là thành viên Hội đồng quản trị của Klaytn phải đảm bảo được tài nguyên máy tính lớn hơn yêu cầu của nền tảng, đồng thời nắm giữ một lượng KLAY nhất định của riêng mình hoặc từ một bên thứ ba. Để hoạt động trơn tru trong việc phát triển và ổn định nền tảng, Klaytn Foundation sẽ đảm nhận nhiều vai trò trong những việc liên quan đến quản trị trong giai đoạn phát triển ban đầu. Tuy nhiên, trong tương lai, các cơ quan khác sẽ dần dần đảm nhận những vai trò lớn hơn trong quy trình đưa ra quyết định và họ sẽ có quyền để tham gia độc lập.

* **Giai đoạn phát triển**: Trong giai đoạn phát triển ban đầu sau khi khởi chạy mạng chính thức, việc điều chỉnh về tham số, phát triển tính năng mới, v.v. phải nhanh chóng được thực hiện. Để làm được như vậy, nhiều vấn đề sẽ được quyết định thông qua việc thu thập ý kiến của các thành viên Hội đồng quản trị của Klaytn, nhà cung cấp dịch vụ và thành viên cộng đồng. Để đảm bảo khả năng ổn định ban đầu, Klaytn Foundation sẽ dẫn dắt quy trình đưa ra quyết định. Ngoài ra, tất cả các vấn đề đã được quyết định cũng sẽ được chia sẻ công khai một cách minh bạch.
* **Giai đoạn ổn định**: Hội đồng quản trị của Klaytn có quyền quản lý đối với nhiều đề xuất và giai đoạn này sẽ bắt đầu dần dần kể từ tháng 1 năm 2021. Đối với các vấn đề đặc biệt, ví dụ như liên quan tới việc phát triển nền tảng, cũng như các sự việc trực tiếp ảnh hưởng tới toàn bộ hệ sinh thái Klaytn, Klaytn Foundation có thể sẽ phải tổ chức thảo luận và thực thi.
* **Giai đoạn phi tập trung**: Sau giai đoạn ổn định, một số thực thể phi truyền thống như DAO và các nhà xây dựng có thể sẽ được đưa vào quá trình ra quyết định để lấy thêm ý kiến. Giai đoạn phi tập trung có thể dần đạt được thông qua nhiều giai đoạn với các quy tắc và người tham gia quản lý khác nhau.


# Đa kênh

Nút Klaytn có thể chạy **Đa kênh**.

Nếu một nút được thực thi với cấu hình đa kênh thì 2 cổng sẽ được thiết lập để giao tiếp. Mặt khác, nếu một nút được thực thi bằng cấu hình đơn kênh, 1 cổng sẽ được thiết lập. Nếu 2 nút đa kênh đều cố kết nối, thì một kết nối sẽ được thiết lập bằng 2 cổng. Nếu không, chúng sẽ dùng 1 cổng để giao tiếp.

Có thể kích hoạt nút đa kênh bằng cờ báo `--multichannel`. Nếu bạn sử dụng [`kend`](/content/installation-guide/deployment/endpoint-node/installation-guide/startup-the-en), cấu hình đa kênh sẽ được kích hoạt theo mặc định do chỉ lệnh `MULTICHANNEL=1` trong [`kend.conf`](/content/installation-guide/deployment/endpoint-node/installation-guide/configuration). Để tắt chế độ đa kênh, vui lòng thay thế chỉ lệnh bằng `MULTICHANNEL=0`. Nếu muốn chạy một nút bằng các cổng cụ thể, bạn có thể sử dụng cờ báo `port` và `subport`. Nếu bạn muốn chỉ định các giá trị cổng của một nút ngang hàng đang kết nối, hãy xem [KNI](/content/klaytn/design/kni).

## Kiến trúc <a href="#architecture" id="architecture"></a>

![Máy chủ đa kênh](/files/DT6cEXqQbuktwgafQy5d)

Hình trên cho thấy kết nối giữa hai nút đa kênh. Hai cổng, cổng chính (A) và cổng phụ (B), truyền tải các thông điệp khác nhau.

* **Cổng chính**(A) được dùng để truyền tải thông điệp liên quan đến khối và giao thức đồng thuận.
  * Các thông điệp về khối bao gồm các yêu cầu và phản hồi của hàm băm, tiêu đề, phần nội dung và biên lai của một khối.
  * Các thông điệp đồng thuận bao gồm Request, Preprepare, Prepare, Commit và RoundChange. Bạn có thể tìm thấy ý nghĩa của các thông điệp này tại [PBFT](/content/klaytn/design/consensus-mechanism#pbft-practical-byzantine-fault-tolerance).
* **Cổng phụ**(B) được dùng để truyền tải các thông báo về giao dịch.

![Máy chủ đơn kênh](/files/oGhUDtIcA7zssIcDatZz)

Hình ảnh thể hiện kết nối giữa hai nút đơn kênh hoặc giữa một nút đơn kênh và một nút đa kênh. Trong trường hợp này, tất cả các thông báo liên quan đến khối, giao dịch và giao thức đồng thuận sẽ được chuyển qua cùng một cổng.

## Cổng <a href="#multichannel-port" id="multichannel-port"></a>

Để đặt số lượng cổng trong KNI, vui lòng tham khảo [lược đồ KNI](/content/klaytn/design/kni).

* Đơn kênh: Một nút đơn kênh sử dụng một cổng (mặc định là 32323).
* Đa kênh: Một nút đa kênh sử dụng hai cổng. Bạn có thể chỉ định các cổng này tại `port` và `subport`. Trong Klaytn, các giá trị mặc định của `port` và `subport` lần lượt là 32323 và 32324.
  * Bạn có thể không đặt `subport` khi kết nối với nút đa kênh. Trong trường hợp này, ban đầu, một nút Klaytn cố kết nối bằng đơn kênh. Trong quá trình tạo kết nối, số lượng cổng thực tế của nút ngang hàng sẽ được tiết lộ. Nếu nút ngang hàng là một nút đa kênh, kết nối hiện hành sẽ bị hủy và một kệt nối khác sẽ được tạo ra với các cổng đã cập nhật.


# KNI

**KNI (Mã định danh mạng lưới Klaytn)** là một lược đồ URL dùng để xác định nút Klaytn. Cú pháp của mã này như sau:

```
kni://<nodeID>@<hostname>:<port>?subport=<subport>&discport=<discport>
```

![Lược đồ KNI](/files/AWnX1L0CABDSnkhgdFbS)

**nodeID** là khóa công khai 512 bit tương ứng với khóa riêng tư của nút. Khóa này được dùng để xác thực giao tiếp với các nút ngang hàng trên mạng p2p.

**hostname** mô tả địa chỉ của một nút, nằm giữa `@` và `:`. Định dạng địa chỉ có thể là một trong những định dạng sau:

* IPv4 phân định bằng dấu chấm thập phân (`192.0.2.1`)
* IPv6 (`[2001:db8::68]`)
* IPv4-mapped IPv6 (`[2001:db8:3c4d:15::abcd:ef12]`)
* Tên miền (`your.node.com`)

**port** được sử dụng để tạo kết nối với các nút ngang hàng thông qua TCP. Trong Klaytn, `port` mặc định là `32323` và `subport` mặc định là `32324`. Lưu ý rằng `subport` mặc định được cấu hình là `port + 1` trong `kend.conf`. Tùy thuộc vào số lượng cổng lắng nghe TCP, Klaytn hỗ trợ hai [loại kết nối](/content/klaytn/design/multiport).

**discport** được dùng để kiểm tra xem những nút lân cận xác định có thể tiếp cận các nút Klaytn hay không và tìm địa chỉ của các nút lân cận để tạo các kết nối mới. Lưu ý rằng đây là cổng UDP. Theo mặc định, cổng UDP hay `discport`, sử dụng cùng một cổng với cổng TCP. Nếu nút sử dụng một cổng khác cho `discport`, thì cổng đó có thể được chỉ định bởi tham số truy vấn `discport`.

Hai URL sau đây hiển thị ví dụ về KNI của một nút có địa chỉ IP `10.0.0.1` và cổng lắng nghe TCP `32323` và `32324`. Nếu `discport` bị bỏ qua thì nó được đặt thành cổng UDP `32323`, giống với giá trị của `port`.

```
kni://a979...163c@10.0.0.1:32323                 # either single-channel or multi-channel peer with omitted subport
kni://a979...163c@10.0.0.1:32323?subport=32324   # multi-channel peer
```

Hai URL tiếp theo hiển thị các ví dụ KNI về các nút có `discport` là `30301`.

```
kni://a979...163c@10.0.0.1:32323?discport=30301                 # either single-channel or multi-channel peer with omitted subport
kni://a979...163c@10.0.0.1:32323?subport=32324&discport=30301   # multi-channel peer
```

Nếu bạn muốn biết cách tạo KNI của một nút, vui lòng tham khảo phần [Tạo khóa nút & nút URI](/content/installation-guide/deployment/core-cell/installation-guide/before-you-install#node-key-node-uri-creation). Lược đồ KNI được dùng trong giao thức khám phá nút, [thiết lập `static-nodes.json` ](/content/installation-guide/deployment/core-cell/installation-guide/proxy-node-setup/configuration#install-static-nodes-json), [API addPeer](/content/dapp/json-rpc/api-references/admin#admin_addpeer), [tùy chọn nút ban đầu](/content/operation-guide/configuration#properties), v.v.


# Các giải pháp mở rộng

### Chuỗi dịch vụ <a href="#service-chain" id="service-chain"></a>

Chuỗi dịch vụ trong Klaytn là các chuỗi khối phụ trợ độc lập với chuỗi chính Klaytn, được điều chỉnh cho từng dApp cần đến cấu hình nút đặc biệt, mức độ bảo mật tùy chỉnh hoặc thông lượng cao đặc biệt khiến việc triển khai dApp đó trên chuỗi chính trở nên bất tiện hoặc không khả thi về mặt kinh tế.

Mặc dù có các giải pháp mở rộng quy mô phi tập trung hoàn toàn, do các giao diện khó dùng, ví dụ như phát sinh thách thức hoặc thoát và hoàn thiện không tức thời, chúng tôi có hướng tiếp cận khác đối với Chuỗi dịch vụ của Klaytn bằng cách đánh đổi khả năng phi tập trung hoàn toàn để nâng cao khả năng sử dụng, hoàn thiện tức thời, hiệu suất cao và tính sẵn có cao.

Chuỗi dịch vụ của Klaytn có thể được sử dụng cho các mục tiêu dịch vụ cụ thể khác nhau và có thể kết nối với chuỗi chính vì nhiều lý do, bao gồm neo dữ liệu (lưu trữ định kỳ các hàm băm khối từ chuỗi dịch vụ lên chuỗi chính để bù cho tính bảo mật của chuỗi dịch vụ bị giảm do số lượng nút ít đi) hoặc chuyển giá trị (chuyển KLAY liên chuỗi, đơn vị giá trị gốc của Klaytn và token do các dApp phát hành).

### Mạng <a href="#network" id="network"></a>

Các chuỗi dịch vụ kết nối với chuỗi chính của Klaytn đều cùng được gọi là Mạng chuỗi dịch vụ. Lưu ý rằng phương pháp kết nối giữa các chuỗi dịch vụ và chuỗi chính có thể thay đổi trong các lần lặp lại trong tương lai của Klaytn.

![Hình 1. Chuỗi chính và Chuỗi dịch vụ của Klaytn](/files/VWXsWNC3RDZ15BAXcOAk)

Hình 1 minh họa mô hình cấu trúc liên kết mạng của các chuỗi dịch vụ đang được sử dụng để đáp ứng nhiều nhu cầu hoạt động kinh doanh khác nhau, được kết nối với chuỗi chính của Klaytn để mở rộng mạng của Klaytn.

![Hình 2. Kết nối giữa Chuỗi chính và Chuỗi dịch vụ sử dụng Mô hình cầu nối chính/cầu nối con](/files/SGN1Xt14um6awlaoCIaw)

Hình 2 minh họa một ví dụ về SCN (Nút đồng thuận chuỗi dịch vụ) được kết nối trực tiếp với EN (Nút điểm cuối) của chuỗi chính của Klaytn bằng mô hình cầu nối con/cầu nối chính trong việc sử dụng các tính năng của chuỗi dịch vụ.

### Tính năng <a href="#features" id="features"></a>

Chuỗi dịch vụ mở rộng và tăng cường Klaytn bằng cách cung cấp một cơ chế toàn vẹn dữ liệu và hỗ trợ chuyển token giữa các chuỗi khác nhau.

#### Neo dữ liệu <a href="#data-anchoring" id="data-anchoring"></a>

Đối với tính toàn vẹn của dữ liệu, Chuỗi dịch vụ có thể tự động neo từng hàm băm của khối chuỗi dịch vụ vào chuỗi chính như một giao dịch đặc biệt. Việc neo dữ liệu này có thể đảm bảo với người dùng dịch vụ rằng dữ liệu trong chuỗi dịch vụ không thể bị thay đổi sau khi được tạo.

#### Chuyển giá trị <a href="#value-transfer" id="value-transfer"></a>

Để giúp các nhà cung cấp dịch vụ (SP) dễ dàng di chuyển người dùng dịch vụ và giá trị trên khắp chuỗi, có thể kích hoạt hoạt động chuyển các token như KLAY (đơn vị giá trị mặc định của Klaytn) và các token Klaytn do các dApp phát hành giữa nhiều chuỗi khác nhau. Người dùng có thể dễ dàng yêu cầu chuyển token đến các chuỗi khác bằng cách gửi một giao dịch đến một hợp đồng đặc biệt, được gọi là hợp đồng bắc cầu.


# Bắt đầu

Dùng thử và làm quen với Klaytn. Chương này là điểm khởi đầu cho hành trình của bạn đến các dApp Klaytn.


# Triển khai hợp đồng thông minh bằng Foundry

![](/files/DQg3RuhRNGqag9kX3W0j)

## Giới thiệu

Foundry là một bộ khung phát triển hợp đồng thông minh, viết bằng ngôn ngữ Rust, cho phép các nhà phát triển quản lý và lập hợp đồng, chạy thử nghiệm, triển khai hợp đồng và tương tác với mạng từ dòng lệnh thông qua các tập lệnh solidity.

Foundry bao gồm bốn công cụ CLI chính, cho phép phát triển hợp đồng thông minh một cách nhanh chóng và theo mô-đun, cụ thể là:

* [Forge](https://github.com/foundry-rs/foundry/tree/master/forge): Bạn có thể triển khai, thử nghiệm và lập hợp đồng thông minh bằng Forge.
* [Cast](https://github.com/foundry-rs/foundry/tree/master/cast): Cast giúp việc tương tác với các hợp đồng thông minh EVM trở nên đơn giản. Trong đó bao gồm các hoạt động lấy dữ liệu chuỗi, gửi giao dịch và những hoạt động khác.
* [Anvil](https://github.com/foundry-rs/foundry/tree/master/anvil): Bạn có cần khởi động một nút cục bộ không? Anvil là một môi trường nút cục bộ do Foundry cung cấp.
* [Chisel](https://github.com/foundry-rs/foundry/blob/master/chisel): REPL solidity nhanh chóng, hữu dụng và chi tiết.

Trong hướng dẫn này, bạn sẽ:

* Tạo một dự án foundry đơn giản.
* Lập và thử nghiệm một hợp đồng thông minh mẫu bằng Foundry.
* Triển khai các hợp đồng thông minh bằng Foundry vào mạng Baobab của Klaytn.
* Khám phá việc phân nhánh mạng chính thức bằng cast và anvil.

## Điều kiện tiên quyết

Để làm theo hướng dẫn này, bạn cần đáp ứng các điều kiện tiên quyết sau:

* Trình biên tập mã: một trình biên tập mã nguồn như [VS-Code](https://code.visualstudio.com/download).
* [Metamask](https://docs.klaytn.foundation/dapp/tutorials/connecting-metamask#install-metamask): được dùng để triển khai hợp đồng, ký giao dịch và tương tác với hợp đồng.
* Điểm cuối RPC: bạn có thể nhận từ một trong những [Nhà cung cấp điểm cuối](https://docs.klaytn.foundation/content/dapp/json-rpc/public-en) được hỗ trợ.
* KLAY thử nghiệm từ [Vòi](https://baobab.wallet.klaytn.foundation/faucet): nạp tiền vào tài khoản với một lượng KLAY vừa đủ.
* Cài đặt [Rust](https://www.rust-lang.org/tools/install) và [Foundry](https://github.com/foundry-rs/foundry#installation).

## Thiết lập môi trường phát triển

Để kiểm tra xem việc cài đặt foundry có thành công không, hãy chạy lệnh dưới đây:

```bash
forge -V
```

**Kết quả đầu ra**

![](/files/mbBQ62zttsXe8nzjg5Fn)

Sau khi cài đặt foundry thành công, bạn sẽ có quyền truy cập vào các công cụ CLI (forge, cast, anvil, chisel) có sẵn trong foundry. Hãy cùng lập dự án foundry bằng các bước sau:

**Bước 1**: Để bắt đầu một dự án mới, hãy chạy lệnh sau:

```bash
forge init foundry_example 
```

**Bước 2**: Điều hướng đến thư mục dự án của bạn.

```bash
cd foundry_example
ls   
```

Sau khi khởi tạo một dự án foundry, thư mục hiện tại của bạn sẽ bao gồm:

* **src**: thư mục mặc định cho các hợp đồng thông minh của bạn.
* **tests**: thư mục mặc định cho các thử nghiệm.
* **foundry.toml**: tập tin cấu hình dự án mặc định.
* **lib**: thư mục mặc định cho các phần phụ thuộc của dự án.
* **script**: thư mục mặc định cho các tập tin tập lệnh solidity.

## Hợp đồng thông minh mẫu

Trong phần này, chúng ta sẽ dùng hợp đồng đối ứng mẫu trong dự án foundry được khởi tạo. Tập tin `counter.sol` trong thư mục `src/` cần phải có dạng:

```solidity
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.13;
contract Counter {
    uint256 public number;
    function setNumber(uint256 newNumber) public {
        number = newNumber;
    }
    function increment() public {
        number++;
    }
}
```

**Hướng dẫn về mã**

Đây là hợp đồng thông minh của bạn. **Dòng 1** cho thấy Foundry sử dụng phiên bản Solidity 0.8.13 hoặc cao hơn. Từ **dòng 4-12**, một hợp đồng thông minh `Counter` đã được tạo. Hợp đồng này chỉ chứa một số mới bằng cách sử dụng hàm **setNumber** và tăng số đó bằng cách gọi ra hàm **increment**.

## Thử nghiệm hợp đồng thông minh

Foundry cho phép chúng ta viết thử nghiệm bằng solidity thay vì javascript như trong các bộ khung phát triển hợp đồng thông mình khác. Trong dự án foundry đã khởi tạo, `test/Counter.t.sol` là ví dụ về một thử nghiệm viết bằng solidity. Mã sẽ có dạng:

```solidity
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.13;
import "forge-std/Test.sol";
import "../src/Counter.sol";
contract CounterTest is Test {
    Counter public counter;
    function setUp() public {
        counter = new Counter();
        counter.setNumber(0);
    }
    function testIncrement() public {
        counter.increment();
        assertEq(counter.number(), 1);
    }
    function testSetNumber(uint256 x) public {
        counter.setNumber(x);
        assertEq(counter.number(), x);
    }
}
```

Mã trên cho thấy bạn đã nhập thư viện tiêu chuẩn của forge và Counter.sol.

Các bài kiểm tra ở trên kiểm tra các điểm sau:

* Số đó có tăng lên không?
* Số đó có bằng với số đã đặt không?

Để kiểm tra xem thử nghiệm của bạn có chạy ổn hay không, hãy chạy lệnh sau:

```bash
forge test
```

**Kết quả đầu ra**

![](/files/y5BT9h93aP6XurCnUQVW)

Để tìm hiểu thêm về việc viết thử nghiệm, thử nghiệm nâng cao và các tính năng khác, hãy tham khảo [Tài liệu của Foundry](https://book.getfoundry.sh/forge/tests).

## Lập hợp đồng

Lập hợp đồng bằng lệnh sau:

```bash
forge build 
```

## Triển khai hợp đồng

Để triển khai một hợp đồng bằng foundry, bạn phải cung cấp một URL RPC và một khóa riêng tư của tài khoản triển khai hợp đồng đó. Hãy xem danh sách [rpc-providers](https://docs.klaytn.foundation/content/dapp/json-rpc/public-en) trên Klaytn để tìm rpc-url của bạn, và tạo một tài khoản bằng [MetaMask](https://docs.klaytn.foundation/dapp/tutorials/connecting-metamask#install-metamask).

**Bước 1**: Để triển khai hợp đồng của bạn trên mạng Baobab của Klaytn, hãy chạy lệnh dưới đây:

```bash
$ forge create --rpc-url <your_rpc_url> --private-key <your_private_key> src/Counter.sol:Counter
```

**Ví dụ**

```bash
forge create --rpc-url https://klaytn-baobab-rpc.allthatnode.com:8551/qtKkeUE8ZEPI2cs0OHloJ6seI4Wfy36N --private-key hhdhdhdhprivatekeyhdhdhdhud src/Counter.sol:Counter
```

**CẢNH BÁO: Hãy thay thế đối số khóa riêng tư bằng khóa riêng tư của bạn từ MetaMask. Hãy cẩn thận và đừng để lộ khóa riêng tư của bạn.**

**Kết quả đầu ra**

![](/files/TwIS9OCJaS4iCeuiJYFH)

**Bước 2**: Mở [Klaytnscope](https://baobab.scope.klaytn.com/tx/0x669e39c9661fdab59aa34989b58b3f89376a93f846a0c71d2858918f58a307e2?tabId=internalTx) để kiểm tra xem hợp đồng đối ứng có được triển khai thành công không.

**Bước 3**: Sao chép và dán hàm băm của giao dịch vào trường tìm kiếm và nhấn Enter. Bạn sẽ thấy hợp đồng vừa được triển khai.

![](/files/5dhiTjLjIS13T41qQTNa)

## Tương tác với hợp đồng

Sau triển khai thành công hợp đồng thông minh của bạn, bạn cần gọi và thực thi các hàm đúng cách. Hãy cùng tương tác với các hợp đồng đã triển khai trên mạng Baobab của Klaytn bằng [Cast](https://book.getfoundry.sh/reference/cast/cast-send.html). Trong phần này, bạn sẽ học cách sử dụng [cast call](https://book.getfoundry.sh/reference/cast/cast-call) để thực thi hàm `chỉ độc` và [cast send](https://book.getfoundry.sh/reference/cast/cast-send) để thực thi các hàm `viết`.

**A. cast call**: Để nhận số được lưu trữ trong hợp đồng, bạn sẽ gọi hàm `number`. Chạy lệnh dưới đây để xem cách hoạt động.

```bash
cast call YOUR_CONTRACT_ADDRESS "number()" --rpc-url RPC-API-ENDPOINT-HERE
```

**Ví dụ**

```bash
cast call 0xe4d576c447733da7ca9197e88d34a74c3c865cff "number()" --rpc-url https://klaytn-baobab-rpc.allthatnode.com:8551/qtKkeUE8ZEPI2cs0OHloJ6seI4Wfy36N
```

**Kết quả đầu ra**

![](/files/WT3bL7foMek2CYPWUYwR)

Bạn sẽ nhận được dữ liệu này dưới định dạng thập lục phân:

```bash
0x0000000000000000000000000000000000000000000000000000000000000000
```

Tuy nhiên, để nhận được kết quả mong muốn, hãy dùng cast để chuyển đổi kết quả trên. Trong trường hợp này, dữ liệu là một số, vì thế bạn có thể đổi nó thành cơ số 10 để nhận được kết quả 0:

```bash
cast --to-base 0x0000000000000000000000000000000000000000000000000000000000000000 10
```

**Kết quả đầu ra**

![](/files/Pdii8l2oK76qQ1tbVRhj)

**B. cast send**: Để ký và xuất bản một giao dịch như thực thi hàm `setNumber` trong hợp đồng đối ứng, hãy chạy lệnh dưới đây:

```bash
cast send --rpc-url=<RPC-URL> <CONTRACT-ADDRESS> “setNumber(uint256)” arg --private-key=<PRIVATE-KEY>
```

**Ví dụ**

```bash
cast send --rpc-url=https://klaytn-baobab-rpc.allthatnode.com:8551/qtKkeUE8ZEPI2cs0OHloJ6seI4Wfy36N  0xe4d576c447733da7ca9197e88d34a74c3c865cff "setNumber(uint256)"  10 --private-key=<private key>
```

**Kết quả đầu ra**

![](/files/fl0j75L4Kdv32vhCaLF9)

**Kiểm tra chéo số**

```bash
cast call 0xe4d576c447733da7ca9197e88d34a74c3c865cff "number()" --rpc-url https://klaytn-baobab-rpc.allthatnode.com:8551/qtKkeUE8ZEPI2cs0OHloJ6seI4Wfy36N
```

**Kết quả đầu ra**

![](/files/NgSHX2gcVfxDuWOXKRhX)

Bạn sẽ nhận được dữ liệu này dưới định dạng thập lục phân:

```bash
0x000000000000000000000000000000000000000000000000000000000000000a
```

Tuy nhiên, để nhận được kết quả mong muốn, hãy dùng cast để chuyển đổi kết quả trên. Trong trường hợp này, dữ liệu là một số, vì thế bạn có thể đổi nó thành cơ số 10 để nhận được kết quả 10:

```bash
cast --to-base 0x000000000000000000000000000000000000000000000000000000000000000a 10
```

**Kết quả đầu ra**

![](/files/PgQSAqSEoZF79TFN8kdp)

## Phân nhánh mạng chính thức bằng Cast và Anvil

Foundry cho phép chúng ta mô phỏng mạng lưới chính thức thành mạng phát triển cục bộ ([Anvil](https://book.getfoundry.sh/reference/anvil/)). Ngoài ra, bạn cũng có thể tương tác và thử nghiệm hợp đồng trên mạng thật bằng [Cast](https://book.getfoundry.sh/reference/cast/).

### Bắt đầu

Khi đã thiết lập và khởi động dự án Foundry xong, bạn có thể mô phỏng mạng lưới chính thức (cypress) bằng cách chạy lệnh dưới đây:

```bash
anvil --fork-url rpc-url
```

**Ví dụ**

```bash
anvil --fork-url https://archive-en.cypress.klaytn.net
```

**Kết quả đầu ra**

![](/files/0dZb0uAQjDyUrTm175Vy)

Sau khi chạy thành công lệnh này, giao diện dòng lệnh của bạn sẽ có dạng như hình trên. Bạn sẽ có 10 tài khoản được tạo ra với các khóa riêng tư và công khai, kèm theo 10.000 token được nạp sẵn. Máy chủ RPC của chuỗi được mô phỏng sẽ nhận và xử lý khối tại `127.0.0.1:8545/`.

Để xác minh rằng bạn đã mô phỏng mạng lưới, bạn có thể truy vấn số khối gần nhất:

```bash
curl --data '{"method":"eth_blockNumber","params":[],"id":1,"jsonrpc":"2.0"}' -H "Content-Type: application/json" -X POST localhost:8545 
```

Bạn có thể chuyển đổi kết quả từ nhiệm vụ trên từ [hex sang decimal](https://www.rapidtables.com/convert/number/hex-to-decimal.html). Bạn sẽ nhận được số khối mới nhất từ lần bạn phân nhánh mạng lưới. Để xác minh điều này, hãy kiểm tra chéo số khối trên [Klaytnscope](https://klaytnscope.com/block/118704896?tabId=txList).

### Hình minh họa

Trong phần này, bạn sẽ tìm hiểu cách để chuyển token oUSDC từ một người có oUSDC sang một tài khoản được tạo bởi Anvil (0x70997970C51812dc3A010C7d01b50e0d17dc79C8 - Bob)

**Chuyển oUSDC**

Đi đến Klaytnscope và tìm người nắm giữ token oUSDC (ở đây). Hãy chọn một tài khoản ngẫu nhiên. Trong ví dụ này, ta sẽ dùng `0x8e61241e0525bd45cfc43dd7ba0229b422545bca`.

Hãy cùng xuất hợp đồng và tài khoản thành các biến của môi trường:

```bash
export BOB=0x70997970C51812dc3A010C7d01b50e0d17dc79C8
export oUSDC=0x754288077d0ff82af7a5317c7cb8c444d421d103
export oUSDCHolder=0x8e61241e0525bd45cfc43dd7ba0229b422545bca
```

Chúng ta có thể kiểm tra số dư của Bob bằng cast call:

```bash
cast call $oUSDC \
  "balanceOf(address)(uint256)" \
  $BOB
```

**Kết quả đầu ra**

![](/files/aVKWpgFRLjfccpkdCiBc)

Tương tự, ta cũng có thể kiểm tra số dư của người nắm giữ oUSDC bằng cast call:

```bash
cast call $oUSDC \
  "balanceOf(address)(uint256)" \
  $oUSDCHolder
```

**Kết quả đầu ra**

![](/files/Kmw5dRnSnsacESjoIoPq)

Hãy cùng chuyển một ít token từ người dùng may mắn này sang cho Alice bằng cast send:

```bash
cast rpc anvil_impersonateAccount $oUSDCHolder
cast send $oUSDC \
--from $oUSDCHolder\
  "transfer(address,uint256)(bool)" \
  $BOB \
 1000000
```

**Kết quả đầu ra**

![](/files/Ra7NzjcBuAw1Dmd1pQv2)

Hãy cùng kiểm tra xem việc chuyển tiền có thành công không:

```bash
cast call $oUSDC \
  "balanceOf(address)(uint256)" \
  $BOB
```

**Kết quả đầu ra**

![](/files/fJ2qJ0XUnKbzhTzpXxWo)

```bash
cast call $oUSDC \
  "balanceOf(address)(uint256)" \
  $oUSDCHolder
```

**Kết quả đầu ra**

![](/files/18L0FIYPnsCXw0weiQj9)

Để được hướng dẫn sâu hơn về foundry, vui lòng tham khảo [Tài liệu Foundry](https://book.getfoundry.sh/). Ngoài ra, bạn có thể tìm thấy cách triển khai mã đầy đủ cho hướng dẫn này trên [GitHub](https://github.com/klaytn/examples/tree/main/foundry).


# Triển khai hợp đồng thông minh bằng Hardhat

![](/files/upqGMqrZcl7gTO3UIQky)

## Giới thiệu

Phần này sẽ hướng dẫn bạn triển khai token Soulbound cho mạng Baobab của Klaytn bằng cách dùng [Hardhat](https://hardhat.org/).

Hardhat là một môi trường phát triển hợp đồng thông minh, có thể giúp bạn:

* Phát triển và lập hợp đồng thông minh.
* Gỡ lỗi, thử nghiệm và triển khai hợp đồng thông minh và dApp.

Token Soul-bound (SBT) là các NFT không thể chuyển nhượng. Nghĩa là khi đã bạn đã có được chúng, bạn sẽ không thể bán hoặc chuyển nhượng cho người dùng khác. Để tìm hiểu thêm về SBT, cách hoạt động và trường hợp sử dụng của chúng, bạn có thể xem [bài viết tham khảo](https://vitalik.ca/general/2022/01/26/soulbound.html) được Vitalik Buterin xuất bản.

Đến cuối hướng dẫn này, bạn sẽ có thể:

* Thiết lập dự án Hardhat trên Klaytn.
* Tạo token soul-bound đơn giản.
* Lập hợp đồng thông minh bằng Hardhat.
* Kiểm tra, triển khai và tương tác với hợp đồng thông minh bằng Hardhat.
* Khám phá tính năng phân nhánh Hardhat.

## Điều kiện tiên quyết

Để làm theo hướng dẫn này, bạn cần đáp ứng các điều kiện tiên quyết sau:

* Trình biên tập mã: một trình biên tập mã nguồn như [VS-Code](https://code.visualstudio.com/download).
* [Metamask](https://docs.klaytn.foundation/dapp/tutorials/connecting-metamask#install-metamask): được dùng để triển khai hợp đồng, ký giao dịch và tương tác với hợp đồng.
* Điểm cuối RPC: bạn có thể nhận từ một trong những [Nhà cung cấp điểm cuối](https://docs.klaytn.foundation/content/dapp/json-rpc/public-en) được hỗ trợ.
* KLAY thử nghiệm từ [Vòi](https://baobab.wallet.klaytn.foundation/faucet): nạp tiền vào tài khoản với một lượng KLAY vừa đủ.
* [NodeJS và NPM](https://nodejs.org/en/)

## Thiết lập môi trường phát triển

Để tận dụng hardhat, chúng ta cần thiết lập môi trường phát triển và cài đặt hardhat. Hãy cùng thực hiện bằng các bước sau:

**Bước 1**: Tạo một thư mục dự án

```bash
mkdir soulbound-tokens
cd soulbound-tokens
```

**Bước 2**: Khởi tạo một dự án npm

Dán lệnh này vào giao diện dòng lệnh để tạo tập tin package.json

```bash
npm init -y
```

**Bước 3**: Cài đặt hardhat và các phần phụ thuộc khác:

* Dán mã dưới đây và giao diện dòng lệnh để cài đặt hardhat

```bash
npm install --save-dev hardhat
```

* Dán mã dưới đây để cài đặt các phần phụ thuộc khác

```bash
npm install dotenv @nomicfoundation/hardhat-toolbox @klaytn/contracts
```

> Lưu ý: Mã này sẽ cài đặt các phần phụ thuộc cần thiết khác cho dự án này, gồm `hardhat`, `hardhat-toolbox`, `klaytn/contract`, `dotenv` cùng các phần khác.

**Bước 4**: Khởi tạo dự án hardhat:

Chạy lệnh dưới đây để khởi tạo một dự án hardhat

```bash
npx hardhat
```

Với hướng dẫn này, bạn sẽ chọn một dự án typescript như bên dưới:

![](/files/ymRjSOPWfu9jx9h1esDH)

Sau khi khởi tạo dự án hardhat, thư mục hiện tại của bạn sẽ bao gồm:

**contracts/** – thư mục này chứa mã hợp đồng thông minh.

**scripts/** – thư mục này chứa các mã để triển khai hợp đồng trên mạng chuỗi khối.

**test/** – thư mục này chứa các bài kiểm tra đơn vị để kiểm tra hợp đồng thông minh của bạn.

**hardhat.config.ts** – tập tin này chứa các cấu hình quan trọng cho công việc của Hardhat và việc triển khai token soul-bound.

**Bước 5**: Tạo tập tin .env

Đến đây, hãy tạo tập tin .env trong thư mục dự án. Tập tin này sẽ giúp chúng ta tải các biến môi trường từ tập tin .env vào process.env.

* Dán lệnh này vào giao diện dòng lệnh để tạo tập tin .env

```bash
touch .env
```

* Sau khi tạo tập tin, hãy cấu hình sao cho tập tin .env sẽ có dạng:

```js
 KLAYTN_BAOBAB_URL= "Your Baobab RPC link"
 PRIVATE_KEY= "your private key copied from MetaMask wallet"
```

**Bước 6**: Thiết lập cấu hình Hardhat

Sửa đổi `hardhat.config.ts` bằng các cấu hình sau:

```js
require("@nomicfoundation/hardhat-toolbox");
require('dotenv').config()


module.exports = {
  solidity: "0.8.17",
  networks: {
    baobab: {
      url: process.env.KLAYTN_BAOBAB_URL || "",
      gasPrice: 250000000000,
      tài khoảns:
        process.env.PRIVATE_KEY !== undefined ? [process.env.PRIVATE_KEY] : [],
    }
  }
};

```

Đến đây, chúng ta đã thiết lập xong môi trường phát triển, hãy bắt đầu soạn hợp đồng thông minh cho token soul-bound.

## Tạo hợp đồng thông minh SBT

Trong phần này, bạn sẽ dùng [Hợp đồng Klaytn](https://github.com/klaytn/klaytn-contracts): một thư viện dành cho việc phát triển hợp đồng thông minh bảo mật, được xây dựng trên nền tảng mã tin cậy do cộng đồng kiểm duyệt. Đây là một phân nhánh các hợp đồng zeppelin mở.

> Lưu ý: Bạn đã cài đặt thư viện này ở **bước 3** của phần `Thiết lập môi trường phát triển`.

**Bước 1**: Chọn thư mục hợp đồng trong ngăn Trình khám phá, nhấp vào nút New File mới và tạo một tập tin có tên là `SBT.sol`

**Bước 2**: Mở tập tin và dán mã sau vào:

```js
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.7;

import "@klaytn/contracts/KIP/token/KIP17/KIP17.sol";
import "@klaytn/contracts/utils/Counters.sol";
import "@klaytn/contracts/access/Ownable.sol";

contract SoulBoundToken is KIP17, Ownable {
    using Counters for Counters.Counter;

    Counters.Counter private _tokenIdCounter;

    constructor() KIP17("SoulBoundToken", "SBT") {}

    function safeMint(address to) public onlyOwner {
        uint256 tokenId = _tokenIdCounter.current();
        _tokenIdCounter.increment();
        _safeMint(to, tokenId);
    }


    function _beforeTokenTransfer(address from, address to, uint256) pure override internal {
        require(from == address(0) || to == address(0), "This a Soulbound token. It cannot be transferred.");
    }

    function _burn(uint256 tokenId) internal override(KIP17) {
        super._burn(tokenId);
    }
}
```

**Hướng dẫn về mã**

Đây là hợp đồng thông minh của bạn. **dòng 1** cho biết Hardhat sử dụng phiên bản Solidity 0.8.7 hoặc cao hơn. Ngoài ra, dòng này còn nhập KIP17.SOL và các hợp đồng hỗ trợ khác. Từ **dòng 6-12**, một hợp đồng thông minh kế thừa KIP17 đã được tạo. Ngoài ra, tên và ký hiệu của token đã được đưa qua trong hàm tạo.

Như bạn có thể thấy trong đoạn mã trên, tên và ký hiệu của token đã được đặt lần lượt là **SoulBoundToken** và **SBT**. Bạn có thể thay đổi tên và ký hiệu của token theo mong muốn.

Điều quan trọng trong hợp đồng này là không cho phép chuyển nhượng token, khiến cho các token được phát hành mang tính chất định danh cá nhân.

## Thử nghiệm hợp đồng thông minh SBT

Trong phần này, chúng ta sẽ kiểm tra một số chức năng của hợp đồng.

**Bước 1**: Trong ngăn Trình khám phá, chọn thư mục kiểm tra và nhấp vào nút Tập tin mới và tạo một tập tin mới với tên là `sbtTest.ts`

**Bước 2**: Sao chép mã dưới đây vào tập tin `sbtTest.ts`.

```js
// This is an example test file. Hardhat will run every *.ts file in `test/`,
// so feel free to add new ones.

// Hardhat tests are normally written with Mocha and Chai.

// We import Chai to use its asserting functions here.
const { expect } = require("chai");

// We use `loadFixture` to share common setups (or fixtures) between tests.
// Using this simplifies your tests and makes them run faster, by taking
// advantage of Hardhat Network's snapshot functionality.
const { loadFixture } = require("@nomicfoundation/hardhat-network-helpers");

// `describe` is a Mocha function that allows you to organize your tests.
// Having your tests organized makes debugging them easier. All Mocha
// functions are available in the global scope.
//
// `describe` receives the name of a section of your test suite, and a
// callback. The callback must define the tests of that section. This callback
// can't be an async function.
describe("Token contract", function () {
  // We define a fixture to reuse the same setup in every test. We use
  // loadFixture to run this setup once, snapshot that state, and reset Hardhat
  // Network to that snapshot in every test.
  async function deployTokenFixture() {
    // Get the ContractFactory and Signers here.
    const sbt = await ethers.getContractFactory("SoulBoundToken");
    const [owner, addr1, addr2] = await ethers.getSigners();

    // To deploy our contract, we just have to call Token.deploy() and await
    // its deployed() method, which happens onces its transaction has been
    // mined.
    const sbtContract = await sbt.deploy();

    await sbtContract.deployed();

    // Fixtures can return anything you consider useful for your tests
    return { sbtContract, owner, addr1, addr2 };
  }

  // You can nest describe calls to create subsections.
  describe("Deployment", function () {
    // `it` is another Mocha function. This is the one you use to define each
    // of your tests. It receives the test name, and a callback function.
    //
    // If the callback function is async, Mocha will `await` it.
    it("Should mint SBT to owner", async function () {
      const { sbtContract, owner } = await loadFixture(deployTokenFixture);
      const safemint = await sbtContract.safeMint(owner.address);
      expect(await sbtContract.ownerOf(0)).to.equal(owner.address);
    });
  });

  describe("Transactions", function () {
    it("Should prohibit token transfer using transferFrom", async function () {
      const { sbtContract, owner, addr1 } = await loadFixture(
        deployTokenFixture
      );

      const safemintTx = await sbtContract.safeMint(owner.address);

      // prohibit token transfer of token id (0) from owner to addr1
      await expect(
        sbtContract.transferFrom(owner.address, addr1.address, 0)
      ).to.be.reverted;
  });

  it("Should prohibit token transfer using safeTransferFrom", async function () {
    const { sbtContract, owner, addr1 } = await loadFixture(
      deployTokenFixture
    );

    const safemintTx = await sbtContract.safeMint(owner.address);

    // prohibit token transfer of token id (0) from owner to addr1
    await expect(sbtContract['safeTransferFrom(address,address,uint256)'](
      owner.address,
      addr1.address,
      0 
  )).to.be.reverted;
});


});

})
```

Trong đoạn mã bạn vừa sao chép, dòng 7 & 12 cho thấy bạn đã nhập expect từ [Chai](https://www.chaijs.com/api/bdd/) và [loadFixture](https://hardhat.org/tutorial/testing-contracts#reusing-common-test-setups-with-fixtures) từ hardhat-network-helpers.

Các bài kiểm tra ở trên kiểm tra các điểm sau:

* Chủ ở hữu của mã token cụ thể và người nhận các đồng token đó có phải là cùng một người không?
* Nó có ngăn chặn việc chuyển nhượng token giữa các tài khoản không?

**Step 3**: Để chạy bài kiểm tra, hãy chạy dòng lệnh dưới đây:

```bash
npx hardhat test test/sbtTest.ts 
```

![](/files/fGvWAKc1TzfsnW0UWj7d)

Để được hướng dẫn sâu hơn về quy trình kiểm tra, vui lòng xem phần [Hardhat testing](https://hardhat.org/hardhat-runner/docs/guides/test-contracts).

## Triển khai hợp đồng thông minh

Tập lệnh là các tập tin JavaScript/Typescript giúp bạn triển khai các hợp đồng vào mạng chuỗi khối. Trong phần này, bạn sẽ tạo tập lệnh cho hợp đồng thông minh.

**Bước 1**: Trong ngăn Trình khám phá, chọn thư mục “script” và nhấp vào nút New File và tạo một tập tin mới với tên là `sbtDeploy.ts`.

**Bước 2**: Sao chép và dán đoạn mã sau vào tập tin.

> Lưu ý: nhập địa chỉ ví MetaMask của bạn vào biến `deployerAdd`.

```js
import { ethers } from "hardhat";

async function main() {

    const deployerAddr = "Your Metamask wallet address";
    const deployer = await ethers.getSigner(deployerAddr);

    console.log(`Deploying contracts with the tài khoản: ${deployer.address}`);
    console.log(`Account balance: ${(await deployer.getBalance()).toString()}`);

  const sbt = await ethers.getContractFactory("SoulBoundToken");
  const sbtContract = await sbt.deploy();


  await sbtContract.deployed();

console.log(`Congratulations! You have just successfully deployed your soul bound tokens.`);
console.log(`SBT contract address is ${sbtContract.address}. You can verify on https://baobab.scope.klaytn.com/tài khoản/${sbtContract.address}`);
}

// We recommend this pattern to be able to use async/await everywhere
// and properly handle errors.
main().catch((error) => {
  console.error(error);
  process.exitCode = 1;
});
```

**Bước 3**: Trong giao diện dòng lệnh, chạy lệnh sau để yêu cầu Hardhat triển khai token SBT của bạn trên Mạng thử nghiệm Klaytn (Baobab)

```bash
npx hardhat run scripts/sbtDeploy.ts --network baobab
```

![](/files/MDPHXLU0hJN6Bp9GE67e)

**Step 4**: Mở [Klaytnscope](https://baobab.scope.klaytn.com/) để kiểm tra xem token SBT đã được triển khai thành công hay chưa.

**Bước 5**: Sao chép và dán địa chỉ hợp đồng đã được triển khai vào trường tìm kiếm rồi nhấn Enter. Bạn sẽ thấy hợp đồng vừa được triển khai.

![](/files/B8wG5QQV2vvuQo71d5b9)

## Phân nhánh Hardhat

Hardhat cung cấp cho các nhà phát triển chức năng mô phỏng mạng chính thức (tại bất kỳ khối cụ thể nào) thành mạng phát triển cục bộ. Một trong những lợi ích chính của tính năng này là cho phép các nhà phát triển tương tác với hợp đồng đã triển khai và cũng có thể thử nghiệm các trường hợp phức tạp.

Để tính năng này hoạt động hiệu quả, bạn cần kết nối với một nút lưu trữ. Bạn có thể đọc thêm về tính năng này [ở đây](https://hardhat.org/hardhat-network/docs/guides/forking-other-networks#forking-other-networks)

### Phân nhánh mạng chính thức

Đến đây, dự án Hardhat của chúng ta đã được thiết lập, hãy cùng phân nhánh mạng chính thức của Klaytn bằng Harhat. Mở giao diện dòng lệnh và chạy lệnh sau

```bash
npx hardhat node --fork <YOUR ARCHIVE NODE URL>

npx hardhat node --fork https://archive-en.cypress.klaytn.net
```

Bạn cũng có thể cấu hình `hardhat.config.ts` - Mạng Hardhat để luôn thực hiện việc này:

```
networks: {
  hardhat: {
    forking: {
      url: "<YOUR ARCHIVE NODE URL>",
    }
  }
}
```

**Kết quả đầu ra**

![](/files/6uXxtnKpP1KrJEUROHtN)

Sau khi chạy thành công lệnh này, giao diện dòng lệnh của bạn sẽ có dạng như hình trên. Bạn sẽ có 20 tài khoản phát triển, đã được nạp sẵn 10.000 token thử nghiệm.

Máy chủ RPC của chuỗi được phân nhánh sẽ nhận và xử lý khối tại địa chỉ `http://127.0.0.1:8545/`. Bạn có thể xác minh mạng lưới được phân nhánh hay chưa bằng cách truy vấn số khối mới nhất. Hãy cùng tạo một cURL đến RPC để nhận số khối. Mở cửa sổ giao diện dòng lệnh mới và dùng lệnh sau:

```bash
curl --data '{"method":"eth_blockNumber","params":[],"id":1,"jsonrpc":"2.0"}' -H "Content-Type: application/json" -X POST localhost:8545 
```

**Kết quả đầu ra**

![](/files/PlmsLTT2hSLdCOQZalDH)

Kết quả đầu ra là một hệ thập lục phân như đã thấy ở trên. Để nhận số khối từ hex, hãy đổi hex thành số thập phân bằng [công cụ](https://www.rapidtables.com/convert/number/hex-to-decimal.html) này. Bạn sẽ nhận được số khối mới nhất từ lần bạn phân nhánh mạng lưới. Bạn có thể xác nhận số khối trên [klaytnscope](https://scope.klaytn.com/).

### Phân nhánh tại một khối

Với hardhat, bạn có thể mô phỏng mạng chính thức tại một khối cụ thể. Trong trường hợp đó, hãy cùng phân nhánh chuỗi tại số khối `105701850`.

```bash
npx hardhat node --fork <YOUR ARCHIVE NODE URL> --fork-block-number 105701850

npx hardhat node --fork https://archive-en.cypress.klaytn.net --fork-block-number 105701850
```

Để xác nhận chuỗi khối được phân nhánh tại một khối cho trước, hãy mở cửa sổ giao diện dòng lệnh mới và dùng lệnh sau:

```bash
curl --data '{"method":"eth_blockNumber","params":[],"id":1,"jsonrpc":"2.0"}' -H "Content-Type: application/json" -X POST localhost:8545 
```

![](/files/5vEh1sQ1X5Eb2ByMZ3Y8)

Kết quả đầu ra trả về hệ thập lục phân, khi được chuyển đổi bằng [công cụ](https://www.rapidtables.com/convert/number/hex-to-decimal.html) này, nó sẽ có giá trị bằng `105701850`.

Để được hướng dẫn sâu hơn về Hardhat, vui lòng tham khảo [Tài liệu về Hardhat](https://hardhat.org/hardhat-runner/docs/getting-started). Ngoài ra, bạn có thể tìm thấy cách triển khai mã đầy đủ cho hướng dẫn này trên [GitHub](https://github.com/klaytn/examples/tree/main/hardhat/soulbound-tokens)


# Triển khai hợp đồng thông minh bằng KEN

![](/files/OoQtFhIemYlnLJKOoF6y)

Trước khi bắt đầu, hãy làm quen với một số thuật ngữ riêng của Klaytn.

* **Nút điểm cuối (EN)**: Nút xử lý các yêu cầu API JSON-RPC gửi đến mạng lưới Klaytn. Nút điểm cuối không tham gia vào thuật toán đồng thuận.
* **KLAY**: đồng tiền mặc định của Klaytn.
* **caver-js**: Triển khai JavaScript của API JSON-RPC của Klaytn.
* **Baobab**: mạng thử nghiệm của Klaytn
* **Cypress**: mạng chính thức của Klaytn

Hướng dẫn từng bước này sẽ hỗ trợ bạn trong quá trình khởi chạy Nút điểm cuối (EN) của mạng thử nghiệm Baobab và xây dựng hợp đồng thông minh cơ bản bằng tài khoản mới của bạn. Hướng dẫn này bao gồm hai phần, thiết lập một EN và triển khai một hợp đồng thông mình qua EN của bạn.

> Hướng dẫn này sử dụng mạng thử nghiệm **Baobab** bởi vì việc triển khai hợp đồng thông minh và gửi giao dịch sẽ cần đến phí giao dịch tính bằng KLAY. Vì mục đích phát triển, bạn có thể nhận KLAY cho mạng thử nghiệm từ [vòi Baobab](https://baobab.wallet.klaytn.foundation/faucet).

## 1. Khởi chạy Nút điểm cuối và thêm KLAY của mạng thử nghiệm Baobab vào Tài khoản của bạn (Linux, Mac) <a href="#id-1-launch-an-endpoint-node-and-add-baobab-testnet-klay-to-your-account-linux-mac" id="id-1-launch-an-endpoint-node-and-add-baobab-testnet-klay-to-your-account-linux-mac"></a>

Phần đầu tiên của hướng dẫn này giải thích cách khởi chạy một EN, tạo một tài khoản mới, và nạp tiền cho tài khoản của bạn bằng vòi trong ví Klaytn Baobab.

* [Khởi chạy nút điểm cuối](/content/getting-started/quick-start/launch-an-en)
* [Nạp tiền vào tài khoản](/content/getting-started/quick-start/top-up-your-account)

## 2. Triển khai hợp đồng thông minh: KlaytnGreeter <a href="#id-2-deploying-a-smart-contract-klaytngreeter" id="id-2-deploying-a-smart-contract-klaytngreeter"></a>

Phần thứ hai của hướng dẫn này chỉ ra các tạo hợp đồng thông minh và triển khai chúng trên mạng thử nghiệm Baobab. Trước khi tiến hành phát triển hợp đồng thông minh, bạn cần thiết lập các công cụ phát triển, cài đặt caver-js và Truffle.

* [Cài đặt các công cụ phát triển](/content/getting-started/quick-start/install-development-tools)
* [Triển khai hợp đồng thông minh](/content/getting-started/quick-start/deploy-a-smart-contract)
* [Kiểm tra quy trình triển khai](/content/getting-started/quick-start/check-the-deployment)


# Khởi chạy nút điểm cuối

## Tải xuống và khởi chạy nút điểm cuối (EN) <a href="#download-and-initialize-an-endpoint-node-en" id="download-and-initialize-an-endpoint-node-en"></a>

Giải nén [gói nhị phân ken](/content/installation-guide/deployment/download#get-the-packages) và sao chép các tập tin vào thư mục klaytn.\
**Lưu ý**: Hãy tải về gói phù hợp có tên bắt đầu bằng `ken`.

Đối với người dùng Mac, hãy giải nén tập tin đã tải về bằng lệnh sau.

```bash
$ tar zxf ken-baobab-vX.X.X-X-darwin-amd64.tar.gz
$ export PATH=$PATH:$PWD/ken-darwin-amd64/bin
```

Đối với người dùng Linux, hãy giải nén tập tin đã tải về bằng lệnh sau.

```bash
$ tar zxf ken-baobab-vX.X.X-X-linux-amd64.tar.gz
$ export PATH=$PATH:$PWD/ken-linux-amd64/bin
```

Bạn nên tạo một thư mục dữ liệu để lưu trữ dữ liệu chuỗi khối. Trong phần hướng dẫn này, chúng ta sẽ tạo một thư mục `kend_home` trong thư mục chính.

```bash
$ mkdir -p ~/kend_home
```

## Cấu hình EN <a href="#configuring-the-en" id="configuring-the-en"></a>

Tập tin cấu hình, `kend.conf`, trong `ken-xxxxx-amd64/conf/`. Để biết thêm thông tin về các tham số có thể định cấu hình, bạn có thể xem phần [Hướng dẫn cấu hình EN](/content/operation-guide/configuration). Để khởi chạy một EN của mạng thử nghiệm Baobab, hãy cập nhật tập tin `kend.conf` phù hợp như sau.

```
# cypress, baobab is only available if you don't specify NETWORK_ID.
NETWORK="baobab"
# if you specify NETWORK_ID, a private network is created.
NETWORK_ID=
...
RPC_API="klay,net" # net module should be opened for truffle later on.
...
DATA_DIR=~/kend_home
```

## Khởi chạy EN <a href="#launching-the-en" id="launching-the-en"></a>

Để khởi chạy EN, hãy thực thi lệnh sau.

```bash
$ kend start
 Starting kend: OK
```

## Kiểm tra EN <a href="#checking-the-en" id="checking-the-en"></a>

Để kiểm tra xem EN có đang chạy hay không, hãy thực thi lệnh sau.

```bash
$ kend trạng thái
kend is running
```

## Kiểm tra bản ghi của EN <a href="#checking-the-log-of-the-en" id="checking-the-log-of-the-en"></a>

Để kiểm tra bản ghi của EN, hãy thực thi lệnh sau.

```bash
$ tail -f ~/kend_home/nhật ký/kend.out
...
INFO[03/26,15:37:49 +09] [5] Imported new chain segment                blocks=1    txs=0  mgas=0.000  elapsed=2.135ms   mgasps=0.000    number=71340 hash=f15511…c571da cache=155.56kB
...
```

## Khắc phục sự cố <a href="#troubleshooting" id="troubleshooting"></a>

Xem phần mục [Khắc phục sự cố](/content/operation-guide/errors-and-troubleshooting) nếu bạn gặp vấn đề trong việc khởi chạy Nút điểm cuối Klaytn.


# Nạp tiền vào tài khoản

## Kết nối với Bảng điều khiển <a href="#attaching-to-the-console" id="attaching-to-the-console"></a>

Nút điểm cuối Klaytn đi kèm bảng điều khiển JavaScript. Từ dòng lệnh của bảng điều khiển, bạn có thể khởi tạo một phần của các lệnh gọi ra API Klaytn đến EN của mình. Để đính kèm vào bảng điều khiển JavaScript, hãy thực thi lệnh sau.

```bash
$ ken attach ~/kend_home/klay.ipc
Welcome to the Klaytn JavaScript console

!instance: Klaytn/vX.X.X/XXXX-XXXX/goX.X.X
 datadir: ~/kend_home
 modules: admin:1.0 debug:1.0 governance:1.0 istanbul:1.0 klay:1.0 miner:1.0 net:1.0 personal:1.0 rpc:1.0 txpool:1.0

 >
```

**LƯU Ý**: Bạn phải đợi đến khi đã tải về tất cả các khối. Nhập `klay.blockNumber` vào bảng điều khiển và kiểm tra xem nó có khớp với số khối hiện tại hay không [tại đây](https://baobab.scope.klaytn.com/)

**LƯU Ý**: Gõ `klay` hoặc`personal` để nhận danh sách các hàm có sẵn.

## Tạo tài khoản Klaytn mới <a href="#creating-a-new-klaytn-account" id="creating-a-new-klaytn-account"></a>

Để tạo một tài khoản Klaytn mới từ bảng điều khiển JavaScript, hãy thực thi lệnh sau. Mã khóa riêng tư của bạn sẽ được mã hóa bằng cụm mật khẩu mà bạn nhập.

```javascript
> personal.newAccount()
Passphrase:  # enter your passphrase
Repeat passphrase:
"0x75a59b94889a05c03c66c3c84e9d2f8308ca4abd" # created tài khoản address
```

Tập tin lưu trữ khóa sẽ được tạo trong thư mục `keystore` thuộc thư mục dữ liệu EN, `DATA_DIR` đặt trong `kend.conf`. Nếu bạn làm theo hướng dẫn mặc định bắt đầu nhanh, thư mục đó sẽ là `~/kend_home/keystore/`.

```javascript
$ ls ~/kend_home/keystore/
UTC--2019-06-24T11-20-15.590879000Z--75a59b94889a05c03c66c3c84e9d2f8308ca4abd
```

## Mở khóa tài khoản Klaytn <a href="#unlocking-the-klaytn-account" id="unlocking-the-klaytn-account"></a>

Để mở khóa một tài khoản đã tạo, hãy thực thi lệnh sau. Lệnh này sẽ mở khóa tài khoản trong 300 giây. **Lưu ý**: Nếu bạn muốn đặt thời gian mở khóa theo cách thủ công, hãy tham khảo \[liên kết]\(../../dapp/json-rpc/api-references/personal.md#personal\_unlocktài khoản) này. **`CẢNH BÁO`**: Việc mở khóa một tài khoản có thể rất nguy hiểm nếu không được thực hiện thận trọng. Có khả năng token của bạn sẽ bị hacker lấy mất nếu hacker xâm nhập được EN của bạn. Để sử dụng phương pháp an toàn hơn, hãy tham khảo mục [hướng dẫn triển khai bằng mã khóa riêng tư](/content/dapp/tutorials/count-dapp/6.-deploy-contract#deploy-method-1-by-private-key)

```javascript
> personal.unlockAccount('75a59b94889a05c03c66c3c84e9d2f8308ca4abd') # tài khoản address to unlock
Unlock tài khoản 75a59b94889a05c03c66c3c84e9d2f8308ca4abd
Passphrase: # enter your passphrase
true
```

## Nhận KLAY cho mạng thử nghiệm từ Vòi Baobab <a href="#getting-testnet-klay-from-the-baobab-faucet" id="getting-testnet-klay-from-the-baobab-faucet"></a>

* Sử dụng vòi Baobab trong Ví Klaytn.
* Truy cập [https://baobab.wallet.klaytn.foundation](https://baobab.wallet.klaytn.foundation/).
* Bạn có thể tạo tài khoản mới từ Ví, hoặc dùng tập tin lưu trữ khóa mà bạn đã tạo từ bảng điều khiển JavaScript EN ở trên để đăng nhập vào Ví.
* Đi đến “Vòi KLAY” từ trình đơn ngăn bên trái, nhấp vào nút “Run Faucet” để nhận 150 KLAY.

  Bạn có thể mở vòi KLAY mỗi 24 giờ một lần.
* Nếu bạn đã tạo một tài khoản mới để nhận KLAY, hãy gửi số KLAY đó đến tài khoản đã được tạo trên EN.

## Kiểm tra số dư trong tài khoản <a href="#checking-the-balance-in-your-account" id="checking-the-balance-in-your-account"></a>

Để xem số dư của tài khoản, hãy thực thi lệnh sau.

Đơn vị mặc định là peb (1 KLAY = 10^18 peb). Bạn có thể tìm hiểu thêm thông tin về các đơn vị của KLAY trong phần [Các đơn vị của KLAY](/content/klaytn/design/klaytn-native-coin-klay#units-of-klay).

```javascript
> klay.getBalance('75a59b94889a05c03c66c3c84e9d2f8308ca4abd') # enter your tài khoản address
1e+21  # 1000 KLAY
```

## Thoát bảng điều khiển <a href="#exiting-the-console" id="exiting-the-console"></a>

Để thoát bảng điều khiển javascript, hãy thực thi lệnh sau.

```javascript
> exit
$
```


# Cài đặt các công cụ phát triển

## Cài đặt caver-js <a href="#installing-caver-js" id="installing-caver-js"></a>

Chúng tôi đề nghị bạn nên tạo một thư mục dự án klaytn để:

```bash
$ mkdir $HOME/klaytn
```

> Bạn cần cài đặt `npm` và `node.js` để tiếp tục. Vui lòng tham khảo [get-npm](https://www.npmjs.com/get-npm) và [node.js](https://nodejs.org/en/) để xem cách cài đặt trên hệ thống của bạn.

[caver-js](/content/dapp/sdk/caver-js) là bộ khung RPC JSON dành cho mạng lưới Klaytn (tương đương với web3.js trong Ethereum). Trước khi cài đặt caver-js, bạn phải tạo tập tin `package.json` qua lệnh `npm init`, sau đó gõ `npm install caver-js` để cài đặt caver-js.

```bash
$ npm init # initialize npm at the klaytn project directory
$ npm install caver-js
```

**LƯU Ý**: Nếu bạn đã cài đặt caver-js, vui lòng cập nhật lên phiên bản mới nhất.

```bash
$ npm cache clean --force # initialize npm cache
$ npm install caver-js@latest # update caver-js to the latest version
```

Nếu bạn nhận được các lỗi sau khi cập nhật caver-js, hãy xóa thư mục `.git` trong thư mục `websocket`.

```bash
npm ERR! path /Users/username/klaytn/node_modules/websocket
npm ERR! code EISGIT
npm ERR! git /Users/username/klaytn/node_modules/websocket: Appears to be a git repo or submodule.
npm ERR! git     /Users/username/klaytn/node_modules/websocket
npm ERR! git Refusing to remove it. Update manually,
npm ERR! git or move it out of the way first.

npm ERR! A complete log of this run can be found in:
npm ERR!     /Users/username/.npm/_nhật ký/2019-06-25T01_49_37_032Z-debug.log​

$ rm /Users/username/klaytn/node_modules/websocket/.git
```

**Lưu ý:** Đối với tất cả các chức năng gọi ra hàm bắt đầu bằng `web3.eth...` in web3.js, nên được thay thế bằng `caver.klay...`.

`web3.eth.sendTransaction({ ... })` (X)

`caver.klay.sendTransaction({ ... })` (O)

## Cài đặt Truffle <a href="#installing-truffle" id="installing-truffle"></a>

Trong bài hướng dẫn này, Truffle được sử dụng để lập và triển khai hợp đồng thông minh được viết bằng Solidity. Hiện tại, Klaytn hỗ trợ Truffle phiên bản 4.1.15. Để biết thêm thông tin về Truffle, hãy tham khảo các trang sau:

* Kho lưu trữ Truffle - <https://github.com/trufflesuite/truffle>
* Tài liệu Truffle - <https://trufflesuite.com/docs>​

Chúng ta có thể cài đặt Truffle theo hai cách

1\) theo cách toàn cục bằng npm, thực thi các lệnh sau:

```bash
$ sudo npm install -g truffle@4.1.15
$ cd /usr/local/lib/node_modules/truffle
$ sudo npm install solc@0.5.6
$ cd -
```

hoặc

2\) theo cách cục bộ, nghĩa là tại thư mục trong máy bạn, thực thi các lệnh sau:

```bash
# Assuming you are in $HOME/klaytn/.
$ npm install truffle@4.1.15
$ cd node_modules/truffle
$ npm install solc@0.5.6
$ cd -
$ ln -s node_modules/truffle/build/cli.bundled.js truffle
$ export PATH=`pwd`:$PATH
```

## Cài đặt vvisp <a href="#installing-vvisp" id="installing-vvisp"></a>

vvisp là một công cụ/bộ khung cli dễ sử dụng để phát triển các hợp đồng thông minh, do [HEACHI LABS](https://henesis.io/) cung cấp. Bạn có thể dễ dàng thiết lập môi trường, triển khai và thực thi các hợp đồng thông minh Klaytn với một lệnh duy nhất. Nó hỗ trợ bộ khung Truffle, vì vậy, các nhà phát triển đã quen thuộc với Truffle có thể dễ dàng sử dụng vvisp.

Ở đây, chúng tôi giới thiệu cách cài đặt vvisp và sử dụng công cụ này để thiết lập môi trường phát triển Klaytn dApp.

* kho lưu trữ vvisp - <https://github.com/HAECHI-LABS/vvisp>
* tài liệu vvisp - <https://github.com/HAECHI-LABS/vvisp/blob/dev/README_KLAYTN.md>

bạn có thể dễ dàng cài đặt vvisp nếu có npm hoặc yarn bằng cách thực thi lệnh sau:

```bash
$ npm install -g @haechi-labs/vvisp
# or if you use yarn
$ yarn global add @haechi-labs/vvisp
```

Sau khi cài đặt xong, bạn có thể sử dụng lệnh vvisp để đảm bảo công cụ này đã được cài đặt đúng cách. **LƯU Ý**: Bạn nên sử dụng phiên bản cao hơn **v2.1.0**.

```bash
$ vvisp
Usage: vvisp <command> [options]

where <command> is one of: compile, console, deploy-contract, deploy-service, flatten, gen-script, init

Options:
  -v, --version  output the version number
  -h, --help     output usage information

Commands:

   compile [files...]                       compile the smart contracts

   console [script-api-path]                run interactive shell to execute contract scripts

   deploy-contract <file> [arguments...]    deploy the smart contracts

   deploy-service                           deploy or upgrade smart contract service using the deployment configure file

   flatten <files...>                       flatten the smart contracts

   gen-script [files...]                    generate javascript libraries communicating the smart contracts

   init [name]                              initialize directory to use vvisp

# you can check installed version.
$ vvisp --version
v2.1.0
```


# Triển khai hợp đồng thông minh

Đến đây, chúng ta đã sẵn sàng phát triển và triển khai các hợp đồng thông minh Klaytn!

## Tạo thư mục dự án <a href="#creating-a-project-directory" id="creating-a-project-directory"></a>

Trước tiên, hãy tạo một thư mục có chứa mã nguồn.

```bash
$ mkdir klaytn-testboard
$ cd klaytn-testboard
```

## Khởi chạy Truffle <a href="#initializing-truffle" id="initializing-truffle"></a>

Khởi chạy Truffle để triển khai hợp đồng.

```bash
$ truffle init
```

## Soạn một hợp đồng thông minh đơn giản bằng Solidity <a href="#writing-a-simple-smart-contract-in-solidity" id="writing-a-simple-smart-contract-in-solidity"></a>

Tạo `KlaytnGreeter.sol` trong thư mục `klaytn-testboard/contracts`.

```bash
$ cd contracts
$ touch KlaytnGreeter.sol
$ vi KlaytnGreeter.sol
```

Viết mã sau trong KlaytnGreeter.sol.

```
pragma solidity 0.5.6;
contract Mortal {
    /* Define variable owner of the type address */
    address payable owner;
    /* This function is executed at initialization and sets the owner of the contract */
    constructor () public { owner = msg.sender; }
    /* Function to recover the funds on the contract */
    function kill() public payable { if (msg.sender == owner) selfdestruct(owner); }
}

contract KlaytnGreeter is Mortal {
    /* Define variable greeting of the type string */
    string greeting;
    /* This runs when the contract is executed */
    constructor (string memory _greeting) public {
        greeting = _greeting;
    }
    /* Main function */
    function greet() public view returns (string memory) {
        return greeting;
    }
}
```

## Sửa đổi tập lệnh di chuyển <a href="#modifying-the-migration-script" id="modifying-the-migration-script"></a>

```bash
$ cd ..
$ cd migrations
$ vi 1_initial_migration.js
```

Sửa đổi `1_initial_migration.js` như sau.

```javascript
const Migrations = artifacts.require("./Migrations.sol");
const KlaytnGreeter = artifacts.require("./KlaytnGreeter.sol");
module.exports = function(deployer) {
  deployer.deploy(Migrations);
  deployer.deploy(KlaytnGreeter, 'Hello, Klaytn');
};
```

## Triển khai hợp đồng thông minh bằng Truffle <a href="#deploying-a-smart-contract-using-truffle" id="deploying-a-smart-contract-using-truffle"></a>

Nhập thông tin mạng của Klaytn vào truffle.js.

**`WARNING`**: Hiện tại, gasPrice của mạng Baobab Klaytn được đặt cố định là 25 Gpeb (**Kết quả trả về là lỗi nếu bạn cố gắng dùng số khác**).

```bash
$ cd ..
$ vi truffle-config.js
```

Sửa đổi cấu hình như sau

```javascript
// truffle-config.js
module.exports = {
    networks: {
        klaytn: {
            host: '127.0.0.1',
            port: 8551,
            from: '0x75a59b94889a05c03c66c3c84e9d2f8308ca4abd', // enter your tài khoản address
            network_id: '1001', // Baobab network id
            gas: 20000000, // transaction gas limit
            gasPrice: 25000000000, // gasPrice of Baobab is 25 Gpeb
        },
    },
    compilers: {
      solc: {
        version: "0.5.6"    // Specify compiler's version to 0.5.6
      }
  }
};
```

Triển khai hợp đồng bằng lệnh sau.

**LƯU Ý**: Sử dụng `--network` để chọn mạng cần triển khai và `--reset` để ghi đè.

**LƯU Ý**: Đảm bảo rằng nút Klaytn của bạn đang chạy.

Địa chỉ hợp đồng của bạn được hiển thị sau \`KlaytnGreeter:

```bash
$ truffle deploy --network klaytn --reset
Using network 'klaytn'.
Running migration: 1_initial_migration.js
  Deploying Migrations...
  ... 0x0f5108bd9e51fe6bf71dfc472577e3f55519e0b5d140a99bf65faf26830acfca
  Migrations: 0x97b1b3735c8f2326a262dbbe6c574a8ea1ba0b7d
  Deploying KlaytnGreeter...
  ... 0xcba53b6090cb4a118359b27293ba95116a8f35f66ae50fbd23ae1081ce9ffb9e
  KlaytnGreeter: [SAVE THIS ADDRESS!!] # this is your smart contract address
Saving successful migration to network...
  ... 0x14eb68727ca5a0ac767441c9b7ab077336f9311f71e9854d42c617aebceeec72
Saving artifacts...
```

**`CẢNH BÁO`**: Kết quả trả về sẽ là lỗi khi tài khoản của bạn bị khóa.

```bash
Running migration: 1_initial_migration.js
  Replacing Migrations...
  ... undefined
Error encountered, bailing. Network state unknown. Review successful transactions manually.
Error: authentication needed: password or unlock
```

Đây là cách bạn mở khóa tài khoản.

```javascript
> personal.unlockAccount('0x775a59b94889a05c03c66c3c84e9d2f8308ca4abd')
Unlock tài khoản 0x75a59b94889a05c03c66c3c84e9d2f8308ca4abd
Passphrase:
true
```

Vậy là bạn đã sẵn sàng. Hãy thử triển khai lại.


# Kiểm tra quy trình triển khai

## Kiểm tra chỉ thị biên dịch đã triển khai bằng caver-js <a href="#checking-the-deployed-byte-code-using-caver-js" id="checking-the-deployed-byte-code-using-caver-js"></a>

Sử dụng `getCode` để kiểm tra chỉ thị biên dịch của hợp đồng thông minh đã triển khai.

Trước tiên, hãy tạo và mở một tệp thử nghiệm.

```bash
$ touch test-klaytn.js
$ open test-klaytn.js
```

Viết mã kiểm tra sau. Đảm bảo bạn nhập địa chỉ hợp đồng mà bạn vừa triển khai.

```javascript
// test-klaytn.js
const Caver = require('caver-js');
const caver = new Caver('http://127.0.0.1:8551');
// enter your smart contract address
const contractAddress = '0x65ca27ed42abeef230a37317a574058ff1372b34'
caver.klay.getCode(contractAddress).then(console.log);
```

Chạy mã.

```bash
$ node test-klaytn.js
0x60806040526004361061004c576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806341c0e1b514610051578063cfae321714610068575b600080fd5b34801561005d57600080fd5b506100666100f8565b005b34801561007457600080fd5b5061007d610189565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156100bd5780820151818401526020810190506100a2565b50505050905090810190601f1680156100ea5780820380516001836020036101000a031916815260200191505b509250505060405180...
```

## Gọi ra các hàm trong Hợp đồng thông minh đã triển khai <a href="#calling-functions-in-the-deployed-smart-contract" id="calling-functions-in-the-deployed-smart-contract"></a>

Dùng JavaScript để gọi ra`greet()` trong hợp đồng.

**LƯU Ý**: Để gọi ra các hàm cụ thể trong hợp đồng thông minh, bạn cần tập tin ABI (Giao dịch nhị phân ứng dụng). Khi triển khai hợp đồng của bạn, Truffle sẽ tự động tạo một tập tin .json tại `./build/contracts/` trong đó có chứa thuộc tính `abi`.

Nối các dòng sau vào mã kiểm tra được viết ở trên.

```javascript
// test-klaytn.js
const Caver = require('caver-js');
const caver = new Caver('http://127.0.0.1:8551');
// enter your smart contract address
const contractAddress = '0x65ca27ed42abeef230a37317a574058ff1372b34'

caver.klay.getCode(contractAddress).then(console.log);
// add lines
const KlaytnGreeter = require('./build/contracts/KlaytnGreeter.json');
// enter your smart contract address
const klaytnGreeter = new caver.klay.Contract(KlaytnGreeter.abi, contractAddress);
klaytnGreeter.methods.greet().call().then(console.log);
```

Chạy mã kiểm tra.

```bash
$ node test-klaytn.js
0x60806040526004361061004c576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806341c0e1b514610051578063cfae321714610068575b600080fd5b34801561005d57600080fd5b506100666100f8565b005b34801561007457600080fd5b5061007d610189565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156100bd5780820151... # This is from caver.klay.getCode
Hello, Klaytn # This is from KlyatnGreeter.methods.greet()
```

**Nếu nhận được dòng "Hello, Klaytn", bạn đã hoàn thành nhiệm vụ. Xin chúc mừng!**


# Quản lý tài khoản

**`CẢNH BÁO`**: Hãy ghi nhớ mật khẩu của bạn. Nếu quên mật khẩu của tài khoản, bạn sẽ không thể truy cập tài khoản đó nữa. **Ở đây không có tùy chọn** ***quên mật khẩu***\*\*. Hãy đừng bao giờ quên mật khẩu. \*\*

Klaytn cung cấp hai công cụ tạo dòng lệnh hữu ích, `ken` và `bảng điều khiển JavaScript`, giúp các nhà phát triển quản lý tài khoản. Xin lưu ý rằng chúng tôi KHÔNG hỗ trợ việc xuất mã khóa riêng tư theo định dạng không được mã hóa.

## ken <a href="#ken" id="ken"></a>

Mã nhị phân nút điểm cuối Klaytn `ken` cho phép quản lý tài khoản thông qua lệnh `tài khoản`. Lệnh `tài khoản` cho phép bạn tạo ra các tài khoản mới, liệt kê tất cả các tài khoản hiện có, nhập mã khóa riêng tư vào một tài khoản mới, chuyển sang định dạng mã khóa mới nhất và thay đổi mật khẩu của bạn.

### Cách sử dụng <a href="#usage" id="usage"></a>

```bash
$ ken tài khoản <command> [options...] [arguments...]
```

**Lệnh**

```bash
$ ken tài khoản -help...
COMMANDS:
     list    Print summary of existing tài khoảns
     new     Create a new tài khoản
     update  Update an existing tài khoản
     import  Import a private key into a new tài khoản
...
```

Bạn có thể nhận thông tin về các lệnh con bằng `ken tài khoản <command> --help`.

```
$ ken tài khoản list --help
list [command options] [arguments...]

Print a short summary of all tài khoảns

KLAY OPTIONS:
  --dbtype value                        Blockchain storage database type ("leveldb", "badger") (default: "leveldb")
  --datadir "/Users/ethan/Library/KEN"  Data directory for the databases and keystore
  --keystore                            Directory for the keystore (default = inside the datadir)

DATABASE OPTIONS:
  --db.no-partitioning  Disable partitioned databases for persistent storage
```

### Thư mục dữ liệu <a href="#data-directory" id="data-directory"></a>

Các tập tin lưu trữ khóa được lưu trữ trong `<DATADIR>/keystore`. Bạn có thể chỉ định thư mục dữ liệu như sau. Chúng tôi đề nghị bạn nên thực thi lệnh `ken tài khoản` với tùy chọn `--datadir`. Chỉ thư mục dữ liệu đến `DATA_DIR` đặt trong `kend.conf` để chia sẻ các tài khoản của bạn một cách suôn sẻ với Nút điểm cuối.

```bash
$ ken tài khoản new --datadir <DATADIR>
$ ken tài khoản new --datadir "~/kend_home"
```

Nếu bạn không chỉ định thư mục dữ liệu, vị trí mặc định sẽ như sau.

* Mac: `~/Library/KEN`
* Linux: `~/.ken`

## Bảng điều khiển JavaScript <a href="#javascript-console" id="javascript-console"></a>

Để kết nối với biểu giá điều khiển JavaScript, EN phải ở trạng thái đang chạy. Để biết thêm thông tin, hãy xem [Khởi chạy EN](/content/getting-started/quick-start/launch-an-en). Khởi chạy EN và kết nối với bảng điều khiển như dưới đây.

### Cách sử dụng <a href="#usage" id="usage"></a>

```bash
$ kend start
Starting kend: OK

$ ken attach ~/kend_home/klay.ipc
Chào mừng bạn đến với bảng điều khiển Klaytn JavaScript!

instance: Klaytn/vX.X.X/XXXX-XXXX/goX.X.X
 datadir: ~/kend_home
 modules: admin:1.0 debug:1.0 governance:1.0 istanbul:1.0 klay:1.0 miner:1.0 net:1.0 personal:1.0 rpc:1.0 txpool:1.0

>
```

**Lệnh**

Gõ `personal` hoặc `klay` để xem danh sách các hàm có sẵn. Trong bài hướng dẫn này, chúng ta sẽ cùng nghiên cứu các hàm sau.

```bash
> personal.newAccount()
> personal.importRawKey()
> personal.unlockAccount()
> klay.tài khoảns
> klay.getBalance()
```

### Thư mục dữ liệu <a href="#data-directory" id="data-directory"></a>

Khi bạn tạo một tài khoản, tập tin lưu trữ khóa sẽ được lưu trữ trong `<DATADIR>keystore`. `<DATADIR>` là `DATA_DIR` được đặt trong `kend.conf`. Nếu bạn làm theo hướng dẫn bắt đầu nhanh với ví dụ đã cho, thư mục đó sẽ phải là `~/kend_home`.


# Tạo tài khoản

## Tạo tài khoản mới <a href="#creating-a-new-account" id="creating-a-new-account"></a>

Quy trình này sẽ tạo một tài khoản mới và in địa chỉ lên màn hình. Một tập tin lưu trữ khóa sẽ được bảo trong thư mục dữ liệu.

**Tập tin lưu trữ khóa Klaytn**

Khi bạn tạo một tài khoản, một tập tin lưu trữ khóa sẽ được tạo ra. Tập tin lưu trữ khóa là phiên bản được mã hóa của mã khóa riêng tư Klaytn mà bạn sẽ dùng để ký các giao dịch của mình. Tên của tập tin lưu trữ khóa có định dạng sau:

* `UTC--<created_at UTC ISO8601>-<address hex>`

Việc chuyển toàn bộ thư mục hoặc tập tin lưu trữ khóa riêng lẻ trong đó giữa các nút Klaytn là an toàn. Xin lưu ý rằng trong trường hợp bạn đang thêm mã khóa vào nút của mình từ một nút khác, thì thứ tự của các tài khoản có thể thay đổi. Vì thế, hãy đảm bảo là bạn không dựa vào chỉ mục trong đoạn mã hoặc tập lệnh của mình.

### ken <a href="#ken" id="ken"></a>

```bash
$ ken tài khoản new --datadir <DATADIR>
$ ken tài khoản new --password <passwordfile> --datadir <DATADIR>
$ ken tài khoản new --password <(echo $mypassword) --datadir <DATADIR>
```

**`CẢNH BẢO`**: Lưu ý rằng việc dùng một tập tin mật khẩu chỉ dành cho quá trình thử nghiệm; bạn không nên lưu mật khẩu vào một tập tin hoặc để lộ mật khẩu dưới bất kỳ hình thức nào khác. Nếu bạn sử dụng tính năng gắn cờ mật khẩu trong một tập tin mật khẩu, hãy đảm bảo rằng không ai có thể thấy hoặc đọc được tập tin này ngoài bạn. Để thực hiện việc này:

```bash
$ touch /path/to/password
$ chmod 700 /path/to/password
$ cat > /path/to/password
I type my pass here
^D
```

### Bảng điều khiển JavaScript <a href="#javascript-console" id="javascript-console"></a>

Trên bảng điều khiển, bạn có thể gọi ra hàm sau để tạo tài khoản:

```javascript
> personal.newAccount("passphrase")
```

Tài khoản được lưu bằng định dạng mã hóa. Bạn **phải** nhớ cụm mật khẩu này để mở khóa tài khoản của mình trong tương lai.

## Nhập tài khoản <a href="#importing-an-account" id="importing-an-account"></a>

Bạn có thể nhập một tài khoản bằng tập tin khóa. Tập tin khóa này được giả định là có chứa một mã khóa riêng tư chưa mã hóa dưới dạng byte thô EC chuẩn được mã hóa thành hex. Nói đơn giản thì nó là một mã khóa riêng tư dưới dạng văn bản thuần, không có `0x` đứng ở đầu.

Tập tin này nhập một khóa riêng tư chưa được mã hóa từ tập tin khóa đã cho, tạo tài khoản mới, tạo một tập tin lưu trữ khóa trong thư mục dữ liệu và in địa chỉ vào bảng điều khiển. Bạn phải nhớ cụm mật khẩu này để mở khóa tài khoản của mình trong tương lai.

**LƯU Ý**: Nếu có thể sao chép trực tiếp các tập tin lưu trữ khóa của mình vào một phiên bản Klaytn khác, bạn không cần đến cơ chế nhập/xuất này/xuất này.

### ken <a href="#ken-1" id="ken-1"></a>

```bash
$ ken account import --datadir <datadir> <keyfile>
$ ken account import --password <passwordfile> --datadir <datadir> <keyfile>
```

### Bảng điều khiển JavaScript <a href="#javascript-console-1" id="javascript-console-1"></a>

```bash
> personal.importRawKey('{private key}', 'mypassword')
"0xfa415bb3e6231f488ff39eb2897db0ef3636dd32"​

// Using a Klaytn wallet key
> personal.importRawKey('{private key}0x000x{address}', 'mypassword')
"0xfa415bb3e6231f488ff39eb2897db0ef3636dd32"
```


# Quản lý tài khoản

## Liệt kê các tài khoản của bạn <a href="#list-your-accounts" id="list-your-accounts"></a>

Lệnh này sẽ trả lại danh sách tất cả các tài khoản được tạo ra trong thư mục dữ liệu.

### ken <a href="#ken" id="ken"></a>

Từ dòng lệnh này, gọi ra CLI bằng:

```bash
$ ken tài khoản list --datadir <DATADIR>
$ ken tài khoản list --datadir ~/kend_home
Account #0: {bfc22a57999459b0c2ce6337deb9287e7a970e02} keystore:///Users/username/kend_home/keystore/UTC--2019-03-26T07-02-58.524962000Z--bfc22a57999459b0c2ce6337deb9287e7a970e02
Account #1: {47bd2e9565cbe1789454718d6cf1778d7ea557aa} keystore:///Users/username/kend_home/keystore/UTC--2019-03-26T07-04-44.840061000Z--47bd2e9565cbe1789454718d6cf1778d7ea557aa
```

**LƯU Ý**: Thứ tự của danh sách tài khoản được trả về có thể thay đổi nếu bạn sao chép tập tin lưu trữ khóa từ các nút khác hoặc xóa các tập tin. Do đó, hãy đảm bảo bạn không dựa vào chỉ mục này, hoặc đảm bảo rằng nếu đã sao chép hoặc xóa các tập tin lưu trữ khóa, bạn sẽ kiểm tra và cập nhật các chỉ mục tài khoản vào các tập lệnh.

### Bảng điều khiển JavaScript <a href="#javascript-console" id="javascript-console"></a>

Khi sử dụng bảng điều khiển:

```javascript
> klay.tài khoảns
["bfc22a57999459b0c2ce6337deb9287e7a970e02", "47bd2e9565cbe1789454718d6cf1778d7ea557aa"]
```

## Mở khóa tài khoản <a href="#unlock-accounts" id="unlock-accounts"></a>

Nếu muốn sử dụng một tài khoản theo cách không tương tác, bạn cần phải mở khóa tài khoản.

### ken <a href="#ken" id="ken"></a>

Bạn có thể mở khóa các tài khoản và bắt đầu EN trên dòng lệnh bằng tùy chọn `--unlock "{address},{address}"`, dòng lệnh này sẽ nhận danh sách tài khoản được phân tách bằng dấu phẩy (ở dạng hex hoặc chỉ mục) làm đối số để có thể mở khóa tài khoản theo chương trình cho một phiên. Việc này rất hữu ích nếu bạn muốn dùng tài khoản của mình từ dApp thông qua RPC. `--unlock` sẽ mở khóa tài khoản đầu tiên trong danh sách. Việc này rất hữu ích khi bạn đã tạo tài khoản theo chương trình, bạn không cần biết tài khoản thực để có thể mở khóa.

Tạo một tài khoản và bắt đầu một nút với tài khoản đã mở khóa:

```bash
$ ken tài khoản new --password <(echo this is not secret) --datadir <DATADIR>
$ ken --password <(echo "this is not secret") --unlock primary --datadir <DATADIR> --rpccorsdomain localhost --verbosity 6 2>> log.log
```

Nếu bạn muốn bắt đầu một nút với một tài khoản cụ thể đã mở khóa, bạn có thể dùng một địa chỉ hoặc chỉ mục đề cập đến vị trí địa chỉ trong danh sách tài khoản (và tương ứng với thứ tự được tạo).

```bash
$ ken --unlock "0" --datadir <DATADIR>
$ ken --unlock "2" --datadir <DATADIR>
$ ken --unlock "bfc22a57999459b0c2ce6337deb9287e7a970e02" --datadir <DATADIR>
```

Dòng lệnh này cho phép bạn mở khóa nhiều tài khoản. Trong trường hợp này, đối số để mở khóa là danh sách địa chỉ hoặc chỉ mục tài khoản được phân tách bằng dấu phẩy.

```bash
$ ken --unlock "0x407d73d8a49eeb85d32cf465507dd71d507100c1,0,5,e470b1a7d2c9c5c6f03bbaa8fa20db6d404a0c32" --datadir <DATADIR>
```

Nếu cấu trúc này được sử dụng theo cách không có tương tác, thì tập tin mật khẩu của bạn sẽ phải chứa mật khẩu tương ứng cho các tài khoản cần dùng, mỗi mật khẩu một dòng.

### Bảng điều khiển JavaScript <a href="#javascript-console" id="javascript-console"></a>

Trên bảng điều khiển, bạn cũng có thể mở khóa các tài khoản (từng tài khoản một) trong một khoảng thời gian (bằng giây).

```javascript
> personal.unlockAccount(address, "password", 300)
```

Xin lưu ý là chúng tôi KHÔNG khuyến khích sử dụng đối số mật khẩu ở đây, vì lịch sử của bảng điều khiển được ghi lại, nên tài khoản của bạn có thể gặp rủi ro. Bạn đã được cảnh báo.

## Kiểm tra số dư tài khoản <a href="#check-account-balance" id="check-account-balance"></a>

### ken <a href="#ken" id="ken"></a>

không có

### Bảng điều khiển JavaScript <a href="#javascript-console" id="javascript-console"></a>

Để kiểm tra số dư tài khoản:

```javascript
> klay.fromPeb(klay.getBalance("{tài khoản}"), "KLAY")
6.5
```

In tất cả số dư bằng hàm JavaScript:

```javascript
function checkAllBalances() {
    var totalBal = 0;
    for (var acctNum in klay.tài khoảns) {
        var acct = klay.tài khoảns[acctNum];

        var acctBal = klay.fromPeb(klay.getBalance(acct), "KLAY");
        totalBal += parseFloat(acctBal);

        console.log("klay.tài khoảns[" + acctNum + "]: \t" + acct + " \tbalance: " + acctBal + "KLAY");

    }

    console.log("Total balance: " + totalBal + " KLAY");
};
```

Sau đó lệnh này có thể được thực thi bằng:

```javascript
> checkAllBalances();
klay.tài khoảns[0]: 0xd1ade25ccd3d550a7eb532ac759cac7be09c2719  balance: 63.11848 KLAY
klay.tài khoảns[1]: 0xda65665fc30803cb1fb7e6d86691e20b1826dee0  balance: 0 KLAY
klay.tài khoảns[2]: 0xe470b1a7d2c9c5c6f03bbaa8fa20db6d404a0c32  balance: 1 KLAY
klay.tài khoảns[3]: 0xf4dd5c3794f1fd0cdc0327a83aa472609c806e99  balance: 6 KLAY
```

Vì hàm này sẽ biến mất sau khi khởi động lại `ken`, nên có thể sẽ hữu ích nếu bạn lưu trữ các hàm thường dùng để sử dụng sau này.

Trước tiên, hãy lưu định nghĩa hàm `checkAllBalances()` vào một tập tin trên máy tính. Ví dụ, `/Users/username/klayload.js`. Sau đó tải tập tin này từ bảng điều khiển tương tác:

```javascript
> loadScript("/Users/username/klayload.js")
true
```

Tập tin sẽ thay đổi môi trường JavaScript của bạn như thể bạn đã nhập lệnh theo cách thủ công. Bạn hãy cứ thoải mái thử nghiệm!


# Môi trường phát triển

**Mạng Klaytn**

* Mạng thử nghiệm Baobab
* Mạng chính thức Cypress

**Nút điểm cuối**

* Bạn cần có [Nút điểm cuối](/content/installation-guide/deployment/endpoint-node) để kết nối với mạng lưới Klaytn và để thực hiện cuộc gọi qua API hoặc gửi một giao dịch.
* `ken` là một nhị phân Nút điểm cuối của Klaytn. `ken` hiển thị hai giao diện, [giao diện dòng lệnh](/content/installation-guide/deployment/endpoint-node/ken-cli-commands) và [JSON-RPC API](/content/dapp/json-rpc). `ken` chạy trên Linux và MacOS.
* `ken` CLI đi kèm với một số chức năng quản lý nút và tiện ích.

**Phát triển hợp đồng thông minh**

* [Klaytn Plugin for Remix](https://ide.klaytn.foundation) - Klaytn Plugin for Remix, một trình biên dịch dựa trên trình duyệt và IDE.
* [Truffle](https://github.com/trufflesuite/truffle) - Một công cụ mã nguồn mở dùng để phát triển các hợp đồng thông minh bằng Solidity.
* [Hardhat](https://hardhat.org/hardhat-runner/docs/getting-started) - Môi trường phát triển cho hợp đồng thông minh và dApps.
* [Foundry](https://book.getfoundry.sh/) - Foundry là một chuỗi công cụ phát triển hợp đồng thông minh.

**Klaytn SDK**

* [caver-js](/content/dapp/sdk/caver-js) : Thư viện JavaScript triển khai các API JSON-RPC của Klaytn.
* [caver-java](/content/dapp/sdk/caver-java) : Thư viện Java triển khai các API JSON-RPC của Klaytn.

**Các bộ công cụ của Klaytn**

* [Klaytnscope](https://scope.klaytn.com/) - Trình khám phá khối và giao dịch.
* [Ví Klaytn](https://wallet.klaytn.com/) - Một công cụ quản lý tài khoản dựa trên trình duyệt.
* [Klaytn Contracts Wizard](https://wizard.klaytn.foundation/) - An interactive generator to bootstrap your smart contract and learn about Klaytn Contracts.


# Nhận KLAY

### Mạng thử nghiệm và Vòi Baobab <a href="#baobab-testnet-and-faucet" id="baobab-testnet-and-faucet"></a>

Vòi **KLAY dùng cho mạng thử nghiệm** chạy trên mạng Baobab. Vòi này có thể được truy cập từ [Ví Klaytn trên Baobab](https://baobab.wallet.klaytn.foundation). Để nhận được KLAY dùng cho mạng thử nghiệm, bạn cần phải có tài khoản Klaytn hợp lệ.

* Tải tài khoản của bạn vào ví bằng mã khóa riêng tư hoặc tập tin lưu trữ khóa. Đồng Đồng KLAY dùng cho mạng thử nghiệm sẽ được gửi đến tài khoản được tải.
* Nhấp vào nút `Run Faucet`, bạn sẽ nhận được 5 KLAY dùng cho mạng thử nghiệm và cập nhật số dư của mình. Xin lưu ý rằng bạn có thể mở vòi cho mỗi tài khoản 24 giờ một lần.

### Danh sách sàn giao dịch KLAY <a href="#klay-exchange-list" id="klay-exchange-list"></a>

KLAY được niêm yết trên nhiều sàn giao dịch. Vui lòng xem danh sách các sàn giao dịch KLAY qua các liên kết sau.

* [Các sàn giao dịch KLAY được niêm yết tại CoinGecko](https://www.coingecko.com/en/coins/klay#markets)
* [Các sàn giao dịch KLAY được niêm yết tại CoinMarketCap](https://coinmarketcap.com/currencies/klaytn/markets/)


# Hợp đồng thông minh

Phần này bao gồm các tài nguyên phát triển để phát triển Hợp đồng thông minh.

Để soạn các hợp đồng thông minh, Klaytn hiện hỗ trợ ngôn ngữ lập trình chính là [Solidity](https://github.com/ethereum/solidity). Solidity được áp dụng trong Klaytn vì đó là ngôn ngữ lập trình hợp đồng tiêu chuẩn *thực tế* cho Ethereum và có một cộng đồng người dùng lớn và tích cực. Nhóm phát triển Klaytn quyết định cung cấp cho người dùng trải nghiệm phát triển quen thuộc để các nhà phát triển dApp Ethereum có thể dễ dàng thử nghiệm hoặc di chuyển các hợp đồng thông minh hiện có của họ sang Klaytn.

Trong tương lai, Klaytn cũng dự định hỗ trợ soạn hợp đồng thông minh bằng các ngôn ngữ lập trình khác. Nhóm phát triển Klaytn đang nghiên cứu các ngôn ngữ lập trình phổ biến khác mà các nhà phát triển có thể sử dụng.


# Solidity - Ngôn ngữ của hợp đồng thông minh

Chương này chỉ mô tả các khái niệm bậc cao, quy trình phát triển và các ví dụ được viết bằng Solidity vì tài liệu tham khảo về Solidity đã được cung cấp đầy đủ trang web chính thức của ngôn ngữ lập trình này. Về tiêu chuẩn kỹ thuật hoặc triển khai ngôn ngữ, vui lòng tham khảo các [Tài liệu tham khảo](#references) dưới đây. Nội dung của chương này được lấy từ nhiều trang web khác nhau được liệt kê trong phần [Tài liệu tham khảo](#references).

## Solidity và Klaytn <a href="#solidity-and-klaytn" id="solidity-and-klaytn"></a>

[Solidity](https://github.com/ethereum/solidity) là một ngôn ngữ lập trình bậc cao kiểu tĩnh, hướng đến hợp đồng, được sử dụng để triển khai các hợp đồng thông minh trên nền tảng Ethereum. Mặc dù Solidity ban đầu được thiết kế cho Ethereum nhưng ngôn ngữ này cũng đủ tổng quát để viết các hợp đồng thông minh. Do đó, có thể sử dụng ngôn ngữ này trên các nền tảng blockchain khác, chẳng hạn như Klaytn.

Klaytn có khả năng tương thích chính thức với Máy ảo Ethereum (EVM) phiên bản **London**. Không đảm bảo tính tương thích ngược với các phiên bản EVM khác trên Klaytn. Do đó, chúng tôi khuyến nghị nên biên dịch mã Solidity với phiên bản mục tiêu Istanbul. Vui lòng tham khảo [cách thiết lập phiên bản EVM của solc](https://solidity.readthedocs.io/en/latest/using-the-compiler.html#setting-the-evm-version-to-target).

{% hint style="success" %}
Nâng cấp giao thức v1.7.0 - thay đổi không tương thích bao gồm các mục liên quan đến lần hard fork **Istanbul** và các mục riêng của Klaytn. Nó đã được kích hoạt từ số khối `#75,373,312` đối với mạng lưới Baobab và `#86,816,005` đối với mạng lưới Cypress.

Nâng cấp giao thức v1.7.3 - thay đổi không tương thích bao gồm Base Fee từ lần hard fork **London**. Nó đã được kích hoạt từ số khối `#80,295,291` đối với mạng lưới Baobab và `#86,816,005` đối với mạng lưới Cypress.

Nâng cấp giao thức v1.8.0 - thay đổi không tương thích bao gồm Base Fee từ lần hard fork **London**. Nó đã được kích hoạt từ số khối `#86,513,895` đối với mạng lưới Baobab và `#86,816,005` đối với mạng lưới Cypress.
{% endhint %}

Có thể sử dụng các công cụ phát triển như [Remix](https://remix.ethereum.org/) (IDE hoạt động trên trình duyệt) và [Truffle](https://github.com/trufflesuite/truffle) (công cụ phát triển) khi phát triển các hợp đồng thông minh cho Klaytn. Nhóm phát triển Klaytn sẽ cố gắng duy trì tính tương thích giữa các công cụ phát triển của Ethereum và Klaytn nhưng cũng có thể lựa chọn cung cấp cho các nhà phát triển hợp đồng thông minh trên Klaytn các phiên bản cải tiến hoặc cập nhật của các công cụ đó khi cần thiết.

Việc sử dụng Remix hoặc Truffle để phát triển hợp đồng thông minh rất tiện lợi nhưng ta cũng có thể sử dụng trình biên dịch Solidity cục bộ bằng cách xây dựng hoặc cài đặt nó theo hướng dẫn được mô tả trong trang web dưới đây:

* [Cài đặt Trình biên dịch Solidity](https://docs.soliditylang.org/en/latest/installing-solidity.html)

Lưu ý rằng có hai trình biên dịch Solidity dòng lệnh:

* *solc*: trình biên dịch với đầy đủ tính năng
  * Được đề cập trong tài liệu Solidity
* *solcjs*: liên kết JavaScript cho *solc*
  * Được duy trì như một dự án riêng [solc-js](https://github.com/ethereum/solc-js)
  * Các tùy chọn dòng lệnh của *solcjs* không tương thích với các tùy chọn của *solc*.

Có thể tham khảo những tài liệu sau đây để bắt đầu sử dụng Solidity:

* [Tài liệu hướng dẫn sử dụng Solidity hàng đầu](https://medium.com/coinmonks/top-solidity-tutorials-4e7adcacced8)

## Cách viết hợp đồng thông minh <a href="#how-to-write-a-smart-contract" id="how-to-write-a-smart-contract"></a>

Phần này trình bày một ví dụ về mã nguồn Solidity để cung cấp cho người đọc ý tưởng về giao diện của hợp đồng thông minh và cách viết hợp đồng. Lưu ý rằng mã nguồn đưa ra trong ví dụ này chỉ nhằm mục đích giải thích và không dành cho mục đích sản xuất. Trong mã nguồn này, `(require)` có nghĩa là dòng này là bắt buộc đối với bất kỳ tập tin nguồn Solidity nào trong khi `(optional)` có nghĩa là dòng này không phải lúc nào cũng cần thiết. Ký hiệu `Ln:` không phải là một phần của mã nguồn Solidity và được đưa ra trong ví dụ chỉ để thể hiện số thứ tự dòng. Không thêm các ký hiệu này vào mã nguồn khi sử dụng trong thực tế.

```
L01: pragma solidity 0.5.12;   // (required) version pragma
L02:
L03: import "filename";        // (optional) importing other source files
L04:
L05: // (optional) smart contract definition
L06: contract UserStorage {
L07:    mapping(address => uint) userData;  // state variable
L08:
L09:    function set(uint x) public {
L10:       userData[msg.sender] = x;
L11:    }
L12:
L13:    function get() public view returns (uint) {
L14:       return userData[msg.sender];
L15:    }
L16:
L17:    function getUserData(address user) public view returns (uint) {
L18:       return userData[user];
L19:    }
L20: }
```

Mã trên khá là dễ hiểu nên nếu bạn đã quen thuộc với bất kỳ ngôn ngữ lập trình nào, bạn có thể bỏ qua phần giải thích dưới đây và chuyển đến phần tiếp theo. Tuy nhiên, đối với những người không hiểu rõ mã trên dùng để làm gì hoặc đối với những người lần đầu biết đến ngôn ngữ lập trình, chúng tôi xin đưa ra một mô tả ngắn về mã nguồn ở bên dưới:

* Các phần nằm trong mã nguồn bắt đầu bằng hai dấu gạch chéo (`//`) là phần ghi chú chứ không phải mã; chúng được sử dụng để chú thích và giải thích mã. Trình biên dịch sẽ bỏ qua phần ghi chú này.
* Câu lệnh `pragma` ở dòng `L01` xác định phiên bản tối thiểu của trình biên dịch. - Câu lệnh `import` ở dòng `L03` nhập tất cả các ký hiệu toàn cục từ "`filename`". `filename` phải là tên một tập tin có thực.
* `L05` - `L20` xác định hợp đồng thông minh có tên là `UserStorage`. Từ khóa `contract` được đặt trước tên hợp đồng và khai báo rằng mã này đại diện cho một hợp đồng thông minh. Các hợp đồng trong Solidity tương tự như các lớp trong các ngôn ngữ hướng đối tượng. Mỗi hợp đồng có thể chứa các khai báo về biến trạng thái, hàm, mã điều chỉnh hàm, sự kiện, kiểu dữ liệu cấu trúc và kiểu dữ liệu enum. Ngoài ra, các hợp đồng có thể kế thừa từ các hợp đồng khác. Đoạn mã trong ví dụ chứa một định nghĩa hợp đồng nhưng một tập tin Solidity có thể chứa nhiều hơn một định nghĩa hợp đồng.
* Ở dòng `L07`, `userData` là biến trạng thái thuộc loại ánh xạ. Biến trạng thái được lưu trữ vĩnh viễn trong bộ nhớ lưu trữ hợp đồng. Biến trạng thái `userData` duy trì một ánh xạ giữa `address` và một giá trị `uint`. Kiểu `address` chứa địa chỉ 20 byte (Klaytn sử dụng địa chỉ 20 byte tương tự như Ethereum).
* Ở dòng `L09`, hàm public `set` được xác định để lưu giá trị `x` vào `userData` cho người gửi thông báo. Biến `msg.sender` là biến đặc biệt được xác định trong Solidity và đại diện cho địa chỉ của người gửi thông báo (*tức là* lệnh gọi hiện tại). Từ khóa `public` có nghĩa là hàm này là một phần của giao diện hợp đồng và có thể được gọi từ bên ngoài hoặc bên trong.
* Các hàm `get` ở dòng `L13` và `getUserData` ở dòng `L17` được khai báo với từ khóa `view`, điều này có nghĩa là các hàm cam kết không thay đổi bất kỳ biến trạng thái nào. Khai báo của các hàm bao gồm `returns (uint)`, có nghĩa là hàm trả về giá trị `uint`.

Để biết thêm thông tin về cú pháp và ngữ nghĩa của ngôn ngữ Solidity, vui lòng tham khảo [Tài liệu Solidity](https://docs.soliditylang.org/).

## Cách biên dịch, triển khai và thực thi hợp đồng <a href="#how-to-compile-deploy-and-execute" id="how-to-compile-deploy-and-execute"></a>

Một cách để biên dịch mã Solidity là sử dụng trình biên dịch dòng lệnh *solc*. Trình biên dịch này có thể tạo các đầu ra khác nhau, từ các tập tin nhị phân và mã assembly đến cây cú pháp trừu tượng (parse tree). Giả sử rằng mã trên đã được lưu trong tập tin `UserStorage.sol` (dòng `L03` không được bao gồm trong tập tin nguồn được hiển thị trên đây), dưới đây là một số ví dụ về cách biên dịch tập tin `UserStorage.sol`.

```bash
$ solc --bin UserStorage.sol
```

* Lệnh này sẽ in kết quả biên dịch dưới dạng mã nhị phân, *tức là* bytecode.

```bash
solc -o output --bin --ast --asm UserStorage.sol
```

* Trình biên dịch tạo một tập tin nhị phân (sử dụng `--bin`), cây cú pháp trừu tượng (sử dụng `--ast`) và mã assembly (sử dụng `--asm`) là các tập tin riêng biệt trong thư mục `output`.

```bash
solc --optimize --bin UserStorage.sol
```

* Để đạt hiệu suất tốt hơn, có thể kích hoạt trình tối ưu hóa trong quá trình biên dịch bằng cách sử dụng cờ `--optimize`.

Dưới đây là một số tài liệu tham khảo để biên dịch, triển khai và thực thi các hợp đồng thông minh.

* [Sử dụng trình biên dịch dòng lệnh Solidity](https://docs.soliditylang.org/en/latest/using-the-compiler.html)
* [Biên dịch hợp đồng bằng Remix](https://remix-ide.readthedocs.io/en/stable/compile.html)
* [Chạy giao dịch với Remix](https://remix-ide.readthedocs.io/en/stable/run.html)
* [Tài liệu hướng dẫn Remix Learneth](https://remix-ide.readthedocs.io/en/latest/remix_tutorials_learneth.html)
* [Biên dịch hợp đồng bằng Truffle](https://trufflesuite.com/docs/truffle/getting-started/compiling-contracts)
* [Triển khai hợp đồng bằng Truffle](https://trufflesuite.com/docs/truffle/getting-started/running-migrations)

LƯU Ý: Mục này sẽ được cập nhật trong tương lai.

## Gỡ lỗi hợp đồng thông minh <a href="#debugging-smart-contracts" id="debugging-smart-contracts"></a>

Việc gỡ lỗi mã Solidity khó hơn so với việc gỡ lỗi mã viết bằng các ngôn ngữ lập trình khác do thiếu các công cụ gỡ lỗi hiệu quả. Dưới đây là một số tài liệu tham khảo về việc gỡ lỗi Solidity.

* [Gỡ lỗi giao dịch bằng Remix](https://remix-ide.readthedocs.io/en/latest/debugger.html)
* [Hướng dẫn về cách gỡ lỗi giao dịch bằng Remix](https://remix-ide.readthedocs.io/en/latest/tutorial_debug.html)
* [Gỡ lỗi hợp đồng bằng Truffle](https://trufflesuite.com/docs/truffle/getting-started/using-the-truffle-debugger/)

LƯU Ý: Mục này sẽ được cập nhật trong tương lai.

## Thực hành tốt nhất về hợp đồng thông minh <a href="#smart-contract-best-practices" id="smart-contract-best-practices"></a>

Việc nghiên cứu và tuân thủ các thực hành tốt nhất trong lập trình Solidity đóng vai trò rất quan trọng để loại bỏ các vấn đề về bảo mật và chất lượng mã trong hợp đồng thông minh của bạn. Dưới đây là một số tài liệu tham khảo về thực hành tốt nhất đối với Solidity.

* [Thực hành bảo mật hợp đồng thông minh](https://github.com/ConsenSys/smart-contract-best-practices)

LƯU Ý: Mục này sẽ được cập nhật trong tương lai.

## Tài liệu tham khảo <a href="#references" id="references"></a>

* [Trang Solidity GitHub](https://github.com/ethereum/solidity)
* [Bộ tài liệu Solidity](https://solidity.readthedocs.io/en/latest/index.html)
* [Bộ tài liệu Remix](https://remix-ide.readthedocs.io/en/latest/)
* [Bộ tài liệu Truffle](https://trufflesuite.com/docs/truffle/)


# Hợp đồng đã lập trước

Klaytn cung cấp một số hợp đồng đã lập trước hữu ích. Những hợp đồng này được thực hiện trực tiếp trong nền tảng dưới dạng triển khai gốc trong hệ thống. Các hợp đồng đã lập trước từ địa chỉ 0x01 đến 0x09 giống như các hợp đồng trong Ethereum. Ngoài ra, Klaytn cũng triển khai các hợp đồng đã lập trước từ 0x3fd đến 0x3ff để hỗ trợ các tính năng mới của Klaytn.

{% hint style="success" %}
LƯU Ý: Ba địa chỉ hợp đồng đã lập trước đã thay đổi và **blake2F** đã được thêm sau khi nâng cấp giao thức `IstanbulEVM`, hay còn gọi là "hard fork".

Số khối nâng cấp giao thức `IstanbulEVM` như sau.

* Mạng thử nghiệm Baobab: `#75373312`
* Mạng chính thức Cypress: `#86816005`

Các hợp đồng được triển khai trước khi nâng cấp giao thức nên sử dụng địa chỉ ban đầu.

* trường hợp 1) Các hợp đồng được triển khai trên Baobab tại số khối `#75373310` nhận diện 0x09, 0x0a và 0x0b lần lượt là địa chỉ của vmLog, feePayer và validateSender, cũng như không thể sử dụng blake2f.
* trường hợp 2) Các hợp đồng được triển khai trên Baobab tại số khối `#75373314` nhận diện 0x09 là địa chỉ của blake2f và nhận diện 0x3fd, 0x3fe và 0xff lần lượt là địa chỉ của vmLog, feePayer và validateSender.

Nếu bạn muốn đọc tài liệu trước đây, vui lòng tham khảo phần [tài liệu trước đây](/content/smart-contract/precompiled-contracts/precompiled-contracts-previous).
{% endhint %}

| hợp đồng đã lập trước | các địa chỉ được sử dụng trong các hợp đồng được triển khai trước khi kích hoạt cập nhật giao thức v1.7.0 | các địa chỉ được sử dụng trong các hợp đồng được triển khai sau khi kích hoạt cập nhật giao thức v1.7.0 |
| --------------------- | --------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------- |
| vmLog                 | 0x09                                                                                                      | 0x3fd                                                                                                   |
| feePayer              | 0x0a                                                                                                      | 0x3fe                                                                                                   |
| validateSender        | 0x0b                                                                                                      | 0x3ff                                                                                                   |

## Địa chỉ 0x01: ecrecover(hash, v, r, s) <a href="#address-0x-01-ecrecover-hash-v-r-s" id="address-0x-01-ecrecover-hash-v-r-s"></a>

Địa chỉ 0x01 triển khai hàm ecrecover. Nó trả về địa chỉ từ chữ ký đã cho bằng cách tính toán một hàm phục hồi của ECDSA. Nguyên mẫu hàm như sau:

```
function ecrecover(bytes32 hash, bytes8 v, bytes32 r, bytes32 s) returns (address);
```

## Địa chỉ 0x02: sha256(data) <a href="#address-0x-02-sha-256-data" id="address-0x-02-sha-256-data"></a>

Địa chỉ 0x02 triển khai hàm băm SHA256. Nó trả về hàm băm SHA256 từ dữ liệu đã cho. Nguyên mẫu hàm như sau:

```
function sha256(bytes data) returns (bytes32);
```

## Địa chỉ 0x03: ripemd160(data) <a href="#address-0x-03-ripemd-160-data" id="address-0x-03-ripemd-160-data"></a>

Địa chỉ 0x03 triển khai hàm băm RIPEMD160. Nó trả về hàm băm RIPEMD160 từ dữ liệu đã cho. Nguyên mẫu hàm như sau:

```
function ripemd160(bytes data) returns (bytes32);
```

## Địa chỉ 0x04: datacopy(data) <a href="#address-0x-04-datacopy-data" id="address-0x-04-datacopy-data"></a>

Địa chỉ 0x04 triển khai hàm datacopy (tức là hàm đồng nhất). Nó trả về dữ liệu đầu vào trực tiếp mà không có bất kỳ sửa đổi nào. Hợp đồng đã lập trước này không được hỗ trợ bởi trình biên dịch Solidity. Có thể sử dụng đoạn mã sau với assembly trực tiếp để gọi hợp đồng đã lập trước này.

```
function callDatacopy(bytes memory data) public returns (bytes memory) {
    bytes memory ret = new bytes(data.length);
    assembly {
        let len := mload(data)
        if iszero(call(gas, 0x04, 0, add(data, 0x20), len, add(ret,0x20), len)) {
            invalid()
        }
    }

    return ret;
}     
```

## Địa chỉ 0x05: bigModExp(base, exp, mod) <a href="#address-0x05-bigmodexp-base-exp-mod" id="address-0x05-bigmodexp-base-exp-mod"></a>

Địa chỉ 0x05 triển khai công thức `base**exp % mod`. Nó trả về kết quả từ dữ liệu đã cho. Hợp đồng đã lập trước này không được hỗ trợ bởi trình biên dịch Solidity. Có thể sử dụng đoạn mã sau để gọi hợp đồng đã lập trước này. Lưu ý rằng mặc dù hợp đồng đã lập trước này hỗ trợ độ dài đầu vào tùy ý, nhưng đoạn mã dưới đây sử dụng độ dài đầu vào cố định làm ví dụ.

```
function callBigModExp(bytes32 base, bytes32 exponent, bytes32 modulus) public returns (bytes32 result) {
    assembly {
        // free memory pointer
        let memPtr := mload(0x40)

        // length of base, exponent, modulus
        mstore(memPtr, 0x20)
        mstore(add(memPtr, 0x20), 0x20)
        mstore(add(memPtr, 0x40), 0x20)

        // assign base, exponent, modulus
        mstore(add(memPtr, 0x60), base)
        mstore(add(memPtr, 0x80), exponent)
        mstore(add(memPtr, 0xa0), modulus)

        // call the precompiled contract BigModExp (0x05)
        let success := call(gas, 0x05, 0x0, memPtr, 0xc0, memPtr, 0x20)
        switch success
        case 0 {
            revert(0x0, 0x0)
        } default {
            result := mload(memPtr)
        }
    }
}
```

## Địa chỉ 0x06: bn256Add(ax, ay, bx, by) <a href="#address-0x-06-bn-256-add-ax-ay-bx-by" id="address-0x-06-bn-256-add-ax-ay-bx-by"></a>

Địa chỉ 0x06 triển khai chức năng cộng điểm trên đường cong elliptic gốc. Nó trả về một điểm trên đường cong elliptic biểu diễn `(ax, ay) + (bx, by)`, trong đó (ax, ay) và (bx, by) là các điểm hợp lệ trên đường cong bn256. Hợp đồng đã lập trước này không được hỗ trợ bởi trình biên dịch Solidity. Có thể sử dụng đoạn mã sau để gọi hợp đồng đã lập trước này.

```
function callBn256Add(bytes32 ax, bytes32 ay, bytes32 bx, bytes32 by) public returns (bytes32[2] memory result) {
    bytes32[4] memory input;
    input[0] = ax;
    input[1] = ay;
    input[2] = bx;
    input[3] = by;
    assembly {
        let success := call(gas, 0x06, 0, input, 0x80, result, 0x40)
        switch success
        case 0 {
            revert(0,0)
        }
    }
}
```

## Địa chỉ 0x07: bn256ScalarMul(x, y, scalar) <a href="#address-0x-07-bn-256-scalarmul-x-y-scalar" id="address-0x-07-bn-256-scalarmul-x-y-scalar"></a>

Địa chỉ 0x07 triển khai phép nhân đường cong elip gốc với giá trị vô hướng. Nó trả về một điểm trên đường cong elliptic biểu diễn `scalar * (x, y)`, trong đó (x, y) là một điểm hợp lệ trên đường cong bn256. Hợp đồng đã lập trước này không được hỗ trợ bởi trình biên dịch Solidity. Có thể sử dụng đoạn mã sau để gọi hợp đồng đã lập trước này.

```
function callBn256ScalarMul(bytes32 x, bytes32 y, bytes32 scalar) public returns (bytes32[2] memory result) {
    bytes32[3] memory input;
    input[0] = x;
    input[1] = y;
    input[2] = scalar;
    assembly {
        let success := call(gas, 0x07, 0, input, 0x60, result, 0x40)
        switch success
        case 0 {
            revert(0,0)
        }
    }
}
```

## Địa chỉ 0x08: bn256Pairing(a1, b1, a2, b2, a3, b3, ..., ak, bk) <a href="#address-0x-08-bn-256-pairing-a-1-b-1-a-2-b-2-a-3-b-3-ak-bk" id="address-0x-08-bn-256-pairing-a-1-b-1-a-2-b-2-a-3-b-3-ak-bk"></a>

Địa chỉ 0x08 triển khai chức năng ghép đôi trên đường cong elliptic để thực hiện xác minh zkSNARK. Để biết thêm thông tin, vui lòng tham khảo [EIP-197](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-197.md). Hợp đồng đã lập trước này không được hỗ trợ bởi trình biên dịch Solidity. Có thể sử dụng đoạn mã sau để gọi hợp đồng đã lập trước này.

```
function callBn256Pairing(bytes memory input) public returns (bytes32 result) {
    // input is a serialized bytes stream of (a1, b1, a2, b2, ..., ak, bk) from (G_1 x G_2)^k
    uint256 len = input.length;
    require(len % 192 == 0);
    assembly {
        let memPtr := mload(0x40)
        let success := call(gas, 0x08, 0, add(input, 0x20), len, memPtr, 0x20)
        switch success
        case 0 {
            revert(0,0)
        } default {
            result := mload(memPtr)
        }
    }
}
```

## Địa chỉ 0x09: blake2F(rounds, h, m, t, f) <a href="#address-0x-3fc-vmlog-str" id="address-0x-3fc-vmlog-str"></a>

Địa chỉ 0x09 triển khai hàm nén BLAKE2b F. Để biết thêm thông tin, vui lòng tham khảo [EIP-152](https://eips.ethereum.org/EIPS/eip-152). Hợp đồng đã lập trước này không được hỗ trợ bởi trình biên dịch Solidity. Có thể sử dụng đoạn mã sau để gọi hợp đồng đã lập trước này.

```
function callBlake2F(uint32 rounds, bytes32[2] memory h, bytes32[4] memory m, bytes8[2] memory t, bool f) public view returns (bytes32[2] memory) {
    bytes32[2] memory output;

    bytes memory args = abi.encodePacked(rounds, h[0], h[1], m[0], m[1], m[2], m[3], t[0], t[1], f);

    assembly {
        if iszero(staticcall(not(0), 0x09, add(args, 32), 0xd5, output, 0x40)) {
            revert(0, 0)
        }
    }

    return output;
}
```

## Địa chỉ 0x3fd: vmLog(str) <a href="#address-0x-3fc-vmlog-str" id="address-0x-3fc-vmlog-str"></a>

Địa chỉ 0x3FD được sử dụng để in chuỗi đã chỉ định `str` vào một tập tin cụ thể hoặc chuyển tiếp cho module ghi bản ghi. Để biết thêm thông tin, vui lòng tham khảo [debug\_setVMLogTarget](/content/dapp/json-rpc/api-references/debug/logging#debug_setvmlogtarget). Lưu ý rằng chỉ nên sử dụng hợp đồng đã lập trước này cho mục đích gỡ lỗi và cần bật tùy chọn `--vmlog` khi khởi động nút Klaytn. Ngoài ra, cấp độ bản ghi của nút Klaytn phải là 4 hoặc cao hơn để xem đầu ra của vmLog. Hợp đồng đã lập trước này không được hỗ trợ bởi trình biên dịch Solidity. Có thể sử dụng đoạn mã sau để gọi hợp đồng đã lập trước này.

```
function callVmLog(bytes memory str) public {
    address(0x3fd).call(str);
}
```

## Địa chỉ 0x3fe: feePayer() <a href="#address-0x-3fd-feepayer" id="address-0x-3fd-feepayer"></a>

Địa chỉ 0x3FE trả về người trả phí của giao dịch đang thực thi. Hợp đồng đã lập trước này không được hỗ trợ bởi trình biên dịch Solidity. Có thể sử dụng đoạn mã sau để gọi hợp đồng đã lập trước này.

```
function feePayer() internal returns (address addr) {
    assembly {
        let freemem := mload(0x40)
        let start_addr := add(freemem, 12)
        if iszero(call(gas, 0x3fe, 0, 0, 0, start_addr, 20)) {
          invalid()
        }
        addr := mload(freemem)
    }
}
```

## Địa chỉ 0x3ff: validateSender() <a href="#address-0x-3fe-validatesender" id="address-0x-3fe-validatesender"></a>

Địa chỉ 0x3FF xác minh chữ ký của người gửi với thông báo. Vì Klaytn \[tách riêng cặp khóa khỏi địa chỉ]\(../../klaytn/design/tài khoảns.md#decoupling-key-pairs-from-addresses), nên cần phải xác minh rằng một chữ ký được ký phù hợp bởi người gửi tương ứng. Để làm điều đó, hợp đồng đã lập trước này nhận ba tham số sau:

* Địa chỉ của người gửi để lấy khóa công khai
* Hàm băm thông báo được sử dụng để tạo chữ ký
* Các chữ ký được ký bởi các khóa riêng tư của người gửi với hàm băm thông báo đã cho

Hợp đồng đã lập trước này xác minh rằng chữ ký đã cho được ký đúng bởi các khóa riêng tư của người gửi. Lưu ý rằng Klaytn hỗ trợ đa chữ ký một cách tự nhiên, điều đó có nghĩa là có thể có nhiều chữ ký. Mỗi chữ ký phải có độ dài là 65 byte.

```
function ValidateSender(address sender, bytes32 msgHash, bytes sigs) public returns (bool) {
    require(sigs.length % 65 == 0);
    bytes memory data = new bytes(20+32+sigs.length);
    uint idx = 0;
    uint i;
    for( i = 0; i < 20; i++) {
        data[idx++] = (bytes20)(sender)[i];
    }
    for( i = 0; i < 32; i++ ) {
        data[idx++] = msgHash[i];
    }
    for( i = 0; i < sigs.length; i++) {
        data[idx++] = sigs[i];
    }
    assembly {
        // skip length header.
        let ptr := add(data, 0x20)
        if iszero(call(gas, 0x3ff, 0, ptr, idx, 31, 1)) {
          invalid()
        }
        return(0, 32)
    }
}
```


# Hợp đồng đã lập trước (Các tài liệu trước)

Klaytn cung cấp một số hợp đồng đã lập trước hữu ích. Những hợp đồng này được thực hiện trực tiếp trong nền tảng dưới dạng triển khai gốc trong hệ thống. Các hợp đồng đã lập trước từ địa chỉ 0x01 đến 0x08 giống như các hợp đồng trong Ethereum. Ngoài ra, Klaytn cũng triển khai các hợp đồng đã lập trước từ 0x09 đến 0x0B để hỗ trợ các tính năng mới của Klaytn.

{% hint style="success" %}
LƯU Ý: Tài liệu này chứa biểu giá gas được sử dụng trước khi kích hoạt nâng cấp giao thức. Nếu bạn muốn nhận tài liệu mới nhất, vui lòng tham khảo [tài liệu mới nhất](/content/smart-contract/precompiled-contracts).
{% endhint %}

## Địa chỉ 0x01: ecrecover(hash, v, r, s) <a href="#address-0x-01-ecrecover-hash-v-r-s" id="address-0x-01-ecrecover-hash-v-r-s"></a>

Địa chỉ 0x01 triển khai hàm ecrecover. Nó trả về địa chỉ từ chữ ký đã cho bằng cách tính toán một hàm phục hồi của ECDSA. Nguyên mẫu hàm như sau:

```
function ecrecover(bytes32 hash, bytes8 v, bytes32 r, bytes32 s) returns (address);
```

## Địa chỉ 0x02: sha256(data) <a href="#address-0x-02-sha-256-data" id="address-0x-02-sha-256-data"></a>

Địa chỉ 0x02 triển khai hàm băm SHA256. Nó trả về hàm băm SHA256 từ dữ liệu đã cho. Nguyên mẫu hàm như sau:

```
function sha256(bytes data) returns (bytes32);
```

## Địa chỉ 0x03: ripemd160(data) <a href="#address-0x-03-ripemd-160-data" id="address-0x-03-ripemd-160-data"></a>

Địa chỉ 0x03 triển khai hàm băm RIPEMD160. Nó trả về hàm băm RIPEMD160 từ dữ liệu đã cho. Nguyên mẫu hàm như sau:

```
function ripemd160(bytes data) returns (bytes32);
```

## Địa chỉ 0x04: datacopy(data) <a href="#address-0x-04-datacopy-data" id="address-0x-04-datacopy-data"></a>

Địa chỉ 0x04 triển khai hàm datacopy (tức là hàm đồng nhất). Nó trả về dữ liệu đầu vào trực tiếp mà không có bất kỳ sửa đổi nào. Hợp đồng đã lập trước này không được hỗ trợ bởi trình biên dịch Solidity. Có thể sử dụng đoạn mã sau với assembly trực tiếp để gọi hợp đồng đã lập trước này.

```
function callDatacopy(bytes memory data) public returns (bytes memory) {
    bytes memory ret = new bytes(data.length);
    assembly {
        let len := mload(data)
        if iszero(call(gas, 0x04, 0, add(data, 0x20), len, add(ret,0x20), len)) {
            invalid()
        }
    }

    return ret;
}     
```

## Địa chỉ 0x05: bigModExp(base, exp, mod) <a href="#address-0x05-bigmodexp-base-exp-mod" id="address-0x05-bigmodexp-base-exp-mod"></a>

Địa chỉ 0x05 triển khai công thức `base**exp % mod`. Nó trả về kết quả từ dữ liệu đã cho. Hợp đồng đã lập trước này không được hỗ trợ bởi trình biên dịch Solidity. Có thể sử dụng đoạn mã sau để gọi hợp đồng đã lập trước này. Lưu ý rằng mặc dù hợp đồng đã lập trước này hỗ trợ độ dài đầu vào tùy ý, nhưng đoạn mã dưới đây sử dụng độ dài đầu vào cố định làm ví dụ.

```
function callBigModExp(bytes32 base, bytes32 exponent, bytes32 modulus) public returns (bytes32 result) {
    assembly {
        // free memory pointer
        let memPtr := mload(0x40)

        // length of base, exponent, modulus
        mstore(memPtr, 0x20)
        mstore(add(memPtr, 0x20), 0x20)
        mstore(add(memPtr, 0x40), 0x20)

        // assign base, exponent, modulus
        mstore(add(memPtr, 0x60), base)
        mstore(add(memPtr, 0x80), exponent)
        mstore(add(memPtr, 0xa0), modulus)

        // call the precompiled contract BigModExp (0x05)
        let success := call(gas, 0x05, 0x0, memPtr, 0xc0, memPtr, 0x20)
        switch success
        case 0 {
            revert(0x0, 0x0)
        } default {
            result := mload(memPtr)
        }
    }
}
```

## Địa chỉ 0x06: bn256Add(ax, ay, bx, by) <a href="#address-0x-06-bn-256-add-ax-ay-bx-by" id="address-0x-06-bn-256-add-ax-ay-bx-by"></a>

Địa chỉ 0x06 triển khai chức năng cộng điểm trên đường cong elliptic gốc. Nó trả về một điểm trên đường cong elliptic biểu diễn `(ax, ay) + (bx, by)`, trong đó (ax, ay) và (bx, by) là các điểm hợp lệ trên đường cong bn256. Hợp đồng đã lập trước này không được hỗ trợ bởi trình biên dịch Solidity. Có thể sử dụng đoạn mã sau để gọi hợp đồng đã lập trước này.

```
function callBn256Add(bytes32 ax, bytes32 ay, bytes32 bx, bytes32 by) public returns (bytes32[2] memory result) {
    bytes32[4] memory input;
    input[0] = ax;
    input[1] = ay;
    input[2] = bx;
    input[3] = by;
    assembly {
        let success := call(gas, 0x06, 0, input, 0x80, result, 0x40)
        switch success
        case 0 {
            revert(0,0)
        }
    }
}
```

## Địa chỉ 0x07: bn256ScalarMul(x, y, scalar) <a href="#address-0x-07-bn-256-scalarmul-x-y-scalar" id="address-0x-07-bn-256-scalarmul-x-y-scalar"></a>

Địa chỉ 0x07 triển khai phép nhân đường cong elip gốc với giá trị vô hướng. Nó trả về một điểm trên đường cong elliptic biểu diễn `scalar * (x, y)`, trong đó (x, y) là một điểm hợp lệ trên đường cong bn256. Hợp đồng đã lập trước này không được hỗ trợ bởi trình biên dịch Solidity. Có thể sử dụng đoạn mã sau để gọi hợp đồng đã lập trước này.

```
function callBn256ScalarMul(bytes32 x, bytes32 y, bytes32 scalar) public returns (bytes32[2] memory result) {
    bytes32[3] memory input;
    input[0] = x;
    input[1] = y;
    input[2] = scalar;
    assembly {
        let success := call(gas, 0x07, 0, input, 0x60, result, 0x40)
        switch success
        case 0 {
            revert(0,0)
        }
    }
}
```

## Địa chỉ 0x08: bn256Pairing(a1, b1, a2, b2, a3, b3, ..., ak, bk) <a href="#address-0x-08-bn-256-pairing-a-1-b-1-a-2-b-2-a-3-b-3-ak-bk" id="address-0x-08-bn-256-pairing-a-1-b-1-a-2-b-2-a-3-b-3-ak-bk"></a>

Địa chỉ 0x08 triển khai chức năng ghép đôi trên đường cong elliptic để thực hiện xác minh zkSNARK. Để biết thêm thông tin, vui lòng tham khảo [EIP-197](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-197.md). Hợp đồng đã lập trước này không được hỗ trợ bởi trình biên dịch Solidity. Có thể sử dụng đoạn mã sau để gọi hợp đồng đã lập trước này.

```
function callBn256Pairing(bytes memory input) public returns (bytes32 result) {
    // input is a serialized bytes stream of (a1, b1, a2, b2, ..., ak, bk) from (G_1 x G_2)^k
    uint256 len = input.length;
    require(len % 192 == 0);
    assembly {
        let memPtr := mload(0x40)
        let success := call(gas, 0x08, 0, add(input, 0x20), len, memPtr, 0x20)
        switch success
        case 0 {
            revert(0,0)
        } default {
            result := mload(memPtr)
        }
    }
}
```

## Địa chỉ 0x09: vmLog(str) <a href="#address-0x-09-vmlog-str" id="address-0x-09-vmlog-str"></a>

Địa chỉ 0x09 được sử dụng để in chuỗi đã chỉ định `str` vào một tập tin cụ thể hoặc chuyển tiếp cho module ghi bản ghi. Để biết thêm thông tin, vui lòng tham khảo [debug\_setVMLogTarget](https://github.com/klaytn/klaytn-docs-vn/blob/main/docs/smart-contract/dapp/json-rpc/api-references/debug/logging.md#debug_setvmlogtarget). Lưu ý rằng chỉ nên sử dụng hợp đồng đã lập trước này cho mục đích gỡ lỗi và cần bật tùy chọn `--vmlog` khi khởi động nút Klaytn. Ngoài ra, cấp độ bản ghi của nút Klaytn phải là 4 hoặc cao hơn để xem đầu ra của vmLog. Hợp đồng đã lập trước này không được hỗ trợ bởi trình biên dịch Solidity. Có thể sử dụng đoạn mã sau để gọi hợp đồng đã lập trước này.

```
function callVmLog(bytes memory str) public {
    address(0x09).call(str);
}
```

## Địa chỉ 0x0A: feePayer() <a href="#address-0x-0-a-feepayer" id="address-0x-0-a-feepayer"></a>

Địa chỉ 0x0A trả về người trả phí của giao dịch đang thực thi. Hợp đồng đã lập trước này không được hỗ trợ bởi trình biên dịch Solidity. Có thể sử dụng đoạn mã sau để gọi hợp đồng đã lập trước này.

```
function feePayer() internal returns (address addr) {
    assembly {
        let freemem := mload(0x40)
        let start_addr := add(freemem, 12)
        if iszero(call(gas, 0x0a, 0, 0, 0, start_addr, 20)) {
          invalid()
        }
        addr := mload(freemem)
    }
}
```

## Địa chỉ 0x0B: validateSender() <a href="#address-0x-0-b-validatesender" id="address-0x-0-b-validatesender"></a>

Địa chỉ 0x0B xác minh chữ ký của người gửi với thông báo. Vì Klaytn \[tách riêng cặp khóa khỏi địa chỉ]\(../klaytn/design/tài khoảns.md#decoupling-key-pairs-from-addresses) nên cần phải xác minh rằng một chữ ký được ký phù hợp bởi người gửi tương ứng. Để làm điều đó, hợp đồng đã lập trước này nhận ba tham số sau:

* Địa chỉ của người gửi để lấy khóa công khai
* Hàm băm thông báo được sử dụng để tạo chữ ký
* Các chữ ký được ký bởi các khóa riêng tư của người gửi với hàm băm thông báo đã cho

Hợp đồng đã lập trước này xác minh rằng chữ ký đã cho được ký đúng bởi các khóa riêng tư của người gửi. Lưu ý rằng Klaytn hỗ trợ đa chữ ký một cách tự nhiên, do đó có thể có nhiều chữ ký. Độ dài của một chữ ký phải là 65 byte.

```
function ValidateSender(address sender, bytes32 msgHash, bytes sigs) public returns (bool) {
    require(sigs.length % 65 == 0);
    bytes memory data = new bytes(20+32+sigs.length);
    uint idx = 0;
    uint i;
    for( i = 0; i < 20; i++) {
        data[idx++] = (bytes20)(sender)[i];
    }
    for( i = 0; i < 32; i++ ) {
        data[idx++] = msgHash[i];
    }
    for( i = 0; i < sigs.length; i++) {
        data[idx++] = sigs[i];
    }
    assembly {
        // skip length header.
        let ptr := add(data, 0x20)
        if iszero(call(gas, 0x0b, 0, ptr, idx, 31, 1)) {
          invalid()
        }
        return(0, 32)
    }
}
```


# IDE và công cụ

Trang này bao gồm danh sách các công cụ phát triển được cung cấp để hỗ trợ việc phát triển hợp đồng thông minh trên Klaytn.

#### [Remix Online IDE](https://github.com/klaytn/klaytn-docs-vn/blob/main/docs/toolkit/klaytn-ide.md) <a href="#remix-ide" id="remix-ide"></a>

* Remix Online IDE là một bộ công cụ đắc lực để phát triển, triển khai, gỡ lỗi và kiểm thử các hợp đồng thông minh tương thích với EVM. Bạn có thể viết, biên dịch, triển khai và thực thi các hợp đồng thông minh trên Klaytn từ Remix IDE bằng cách sử dụng Plugin Klaytn.

#### [Klaytn Contracts Wizard](https://wizard.klaytn.foundation/) <a href="#klaytn-contract-wizard" id="klaytn-contract-wizard"></a>

* Klaytn Contracts Wizard is an interactive generator to bootstrap your smart contract and learn about Klaytn Contracts. This is based on OpenZeppelin Wizard.

#### [Truffle](/content/smart-contract/ide-and-tools/truffle) <a href="#truffle" id="truffle"></a>

* Truffle là công cụ cho phép biên dịch và triển khai các hợp đồng thông minh Klaytn viết bằng ngồn ngữ Solidity. Hiện tại, Klaytn hỗ trợ Truffle lên đến phiên bản Truffle v5.0.26.

#### [Kaikas](/content/dapp/developer-tools/getting-started/kaikas) <a href="#kaikas" id="kaikas"></a>

* Kaikas là ví tiện ích của trình duyệt cho Mạng lưới Klaytn. Kaikas cho phép bạn lưu trữ, tương tác với KLAY và các token trên nền tảng Klaytn của bạn. Kaikas cũng cho phép bạn ký giao dịch từ các dApp Klaytn hoạt động trên web ngay lập tức.

#### [Ví Klaytn](/content/dapp/developer-tools/getting-started/klaytn-wallet) <a href="#klaytn-wallet" id="klaytn-wallet"></a>

* Ví Klaytn là công cụ quản lý tài khoản chạy trên trình duyệt dành cho nhà phát triển ứng dụng phi tập trung (dApp). Bạn có thể tạo/tải về tài khoản, xem số dư tài khoản và chuyển KLAY. Bạn cũng có thể đăng ký token Klaytn của chính mình để kiểm thử các hành vi cơ bản.

#### [Klaytnscope](/content/dapp/developer-tools/getting-started-2/klaytnscope) <a href="#klaytnscope" id="klaytnscope"></a>

* Klaytnscope là trình khám phá khối cho mạng lưới Klaytn. Bạn có thể duyệt và kiểm tra giao dịch của mình trên trình duyệt.


# Truffle

## Khả năng tương thích với Truffle <a href="#compatibility-with-truffle" id="compatibility-with-truffle"></a>

Trong Klaytn, một hợp đồng thông minh được viết bằng Solidity có thể được biên dịch và triển khai thông qua Truffle. Hiện tại, Klaytn hỗ trợ đến Truffle v5.0.26, phiên bản mới nhất vào thời điểm tạo bài viết này. Vui lòng tìm thông tin chi tiết về Truffle trên các trang web bên dưới.

* [Tổng quan về Truffle](https://trufflesuite.com/docs/truffle/overview)
* [Kho lưu trữ Truffle](https://github.com/trufflesuite/truffle)

Bạn có thể cài đặt Truffle như sau:

```
$ sudo npm install -g truffle
```

Nếu bạn có EN cục bộ đang chạy, bạn có thể triển khai hợp đồng trực tiếp với khung truffle. Để biết thêm chi tiết, hãy tham khảo [liên kết](/content/getting-started/quick-start/deploy-a-smart-contract#deploying-a-smart-contract-using-truffle) này.

Nếu bạn muốn triển khai với nút EN từ xa, bạn nên sử dụng [truffle-hdwallet-provider-klaytn](https://www.npmjs.com/package/truffle-hdwallet-provider-klaytn).

## Định cấu hình truffle-hdwallet-provider-klaytn <a href="#configuring-truffle-hdwallet-provider-klaytn" id="configuring-truffle-hdwallet-provider-klaytn"></a>

truffle-hdwallet-provider-klaytn là một nhà cung cấp ví JavaScript HD được rẽ nhánh từ truffle-hdwallet-provider.

Cài đặt như sau:

```
$ nvm use 10
$ yarn install truffle-hdwallet-provider-klaytn@1.0.18
```

```
$ nvm use 12 # for node v12 and higher
$ yarn install truffle-hdwallet-provider-klaytn@1.4.1
```

Thiết lập `truffle-config.js` như bên dưới.

### Sử dụng thuật ghi nhớ <a href="#using-a-mnemonic" id="using-a-mnemonic"></a>

```javascript
const HDWalletProvider = require("truffle-hdwallet-provider-klaytn");

const mnemonic = "mountains supernatural bird ...";

module.exports = {
  networks: {
    development: {
      host: "localhost",
      port: 8551,
      network_id: "*", // Match any network id
    },
    klaytn: {
      provider: () => {
        const mnemonic = JSON.parse(
          fs.readFileSync(path.resolve(__dirname) + "/mnemonics.js")
        );

        return new HDWalletProvider(
          mnemonic,
          "https://public-en-baobab.klaytn.net",
          0,
          mnemonic.length
        );
      },
      network_id: "1001", //Klaytn baobab testnet's network id
      gas: "8500000",
      gasPrice: null,
    },
    kasBaobab: {
      provider: () => {
        const option = {
          headers: [
            {
              name: "Authorization",
              value:
                "Basic " +
                Buffer.from(accessKeyId + ":" + secretAccessKey).toString(
                  "base64"
                ),
            },
            { name: "x-chain-id", value: "1001" },
          ],
          keepAlive: false,
        };
        return new HDWalletProvider(
          mnemonic,
          new Caver.providers.HttpProvider(
            "https://node-api.klaytnapi.com/v1/klaytn",
            option
          )
        );
      },
      network_id: "1001", //Klaytn baobab testnet's network id
      gas: "8500000",
      gasPrice: "25000000000",
    },
    kasCypress: {
      provider: () => {
        const option = {
          headers: [
            {
              name: "Authorization",
              value:
                "Basic " +
                Buffer.from(accessKeyId + ":" + secretAccessKey).toString(
                  "base64"
                ),
            },
            { name: "x-chain-id", value: "8217" },
          ],
          keepAlive: false,
        };
        return new HDWalletProvider(
          cypressMnemonic,
          new Caver.providers.HttpProvider(
            "https://node-api.klaytnapi.com/v1/klaytn",
            option
          )
        );
      },
      network_id: "8217", //Klaytn baobab testnet's network id
      gas: "8500000",
      gasPrice: "25000000000",
    },
    baobab: {
      provider: () => {
        return new HDWalletProvider(mnemonic, "http://your.baobab.en:8551");
      },
      network_id: "1001", //Klaytn baobab testnet's network id
      gas: "8500000",
      gasPrice: null,
    },
    cypress: {
      provider: () => {
        return new HDWalletProvider(mnemonic, "http://your.cypress.en:8551");
      },
      network_id: "8217", //Klaytn mainnet's network id
      gas: "8500000",
      gasPrice: null,
    },
  },
};
```

### Sử dụng khóa riêng tư <a href="#using-a-private-key" id="using-a-private-key"></a>

```javascript
const HDWalletProvider = require("truffle-hdwallet-provider-klaytn");

const privateKey = "0x123 ...";

module.exports = {
  networks: {
    development: {
      host: "localhost",
      port: 8551,
      network_id: "*", // Match any network id
    },
    klaytn: {
      provider: () => {
        const pks = JSON.parse(
          fs.readFileSync(path.resolve(__dirname) + "/privateKeys.js")
        );

        return new HDWalletProvider(
          pks,
          "https://public-en-baobab.klaytn.net",
          0,
          pks.length
        );
      },
      network_id: "1001", //Klaytn baobab testnet's network id
      gas: "8500000",
      gasPrice: null,
    },
    kasBaobab: {
      provider: () => {
        const option = {
          headers: [
            {
              name: "Authorization",
              value:
                "Basic " +
                Buffer.from(accessKeyId + ":" + secretAccessKey).toString(
                  "base64"
                ),
            },
            { name: "x-chain-id", value: "1001" },
          ],
          keepAlive: false,
        };
        return new HDWalletProvider(
          privateKey,
          new Caver.providers.HttpProvider(
            "https://node-api.klaytnapi.com/v1/klaytn",
            option
          )
        );
      },
      network_id: "1001", //Klaytn baobab testnet's network id
      gas: "8500000",
      gasPrice: "25000000000",
    },
    kasCypress: {
      provider: () => {
        const option = {
          headers: [
            {
              name: "Authorization",
              value:
                "Basic " +
                Buffer.from(accessKeyId + ":" + secretAccessKey).toString(
                  "base64"
                ),
            },
            { name: "x-chain-id", value: "8217" },
          ],
          keepAlive: false,
        };
        return new HDWalletProvider(
          cypressPrivateKey,
          new Caver.providers.HttpProvider(
            "https://node-api.klaytnapi.com/v1/klaytn",
            option
          )
        );
      },
      network_id: "8217", //Klaytn baobab testnet's network id
      gas: "8500000",
      gasPrice: "25000000000",
    },
    baobab: {
      provider: () => {
        return new HDWalletProvider(privateKey, "http://api.baobab.klaytn.net:8651");
      },
      network_id: "1001", //Klaytn baobab testnet's network id
      gas: "8500000",
      gasPrice: null,
    },
    cypress: {
      provider: () => {
        return new HDWalletProvider(privateKey, "https://public-en-cypress.klaytn.net");
      },
      network_id: "8217", //Klaytn mainnet's network id
      gas: "8500000",
      gasPrice: null,
    },
  },
};
```

**CẢNH BÁO: Đặc biệt cẩn trọng không để lộ mã ghi nhớ hoặc khóa riêng tư của bạn.**

Triển khai trên Klaytn:

```bash
$ truffle deploy --network baobab  # testnet
$ truffle deploy --network cypress # mainnet
```

Thực hiện giao dịch trên Klaytn : (sử dụng ví dụ từ [Bắt đầu nhanh Tài liệu Truffle - Tạo dự án](https://www.trufflesuite.com/docs/truffle/quickstart#creating-a-project))

```bash
$ truffle console --network baobab
truffle(baobab)> Migrations.deployed().then(function(instance) {return instance.setCompleted(3)}) // making transaction
{
  tx: '0x734676311194c1ab8e004e2990e414b7b47a9d0a8506682707f5db03fa6dcee0',
  receipt: {
    blockHash: '0xdf9d77ef893a70b3a3f073525cdf5b2ee36620a3ac81815437788e4cf121678d',
    blockNumber: 65284860,
    contractAddress: null,
    from: '0x50c82047a414d2aad88ae67a5f02c311d2d86e69',
    gas: '0x500000',
    gasPrice: '0x5d21dba00',
    gasUsed: 27001,
    input: '0xfdacd5760000000000000000000000000000000000000000000000000000000000000003',
    nhật ký: [],
    nhật kýBloom: '0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000',
    nonce: '0x1047',
    senderTxHash: '0x734676311194c1ab8e004e2990e414b7b47a9d0a8506682707f5db03fa6dcee0',
    signatures: [ [Object] ],
    trạng thái: true,
    to: '0x69527b5f0078ae1757b631af155fa9be21ef6a85',
    transactionHash: '0x734676311194c1ab8e004e2990e414b7b47a9d0a8506682707f5db03fa6dcee0',
    transactionIndex: 0,
    type: 'TxTypeLegacyTransaction',
    typeInt: 0,
    value: '0x0',
    cumulativeGasUsed: undefined,
    rawLogs: []
  },
  nhật ký: []
}

truffle(baobab)> Migrations.deployed().then(function(instance) {return instance.last_completed_migration.call()}) // read public variable
BN { negative: 0, words: [ 3, <1 empty item> ], length: 1, red: null }
```


# Hợp đồng mẫu


# KlaytnGreeter

`KlaytnGreeter` là hợp đồng đơn giản thực hiện trả về thông báo chào mừng. Thông báo chào mừng được thiết lập khi hợp đồng được triển khai.

## Soạn KlaytnGreeter <a href="#writing-klaytngreeter" id="writing-klaytngreeter"></a>

```
pragma solidity 0.5.6;
contract Mortal {
    /* Define variable owner of the type address */
    address payable owner;
    /* This function is executed at initialization and sets the owner of the contract */
    constructor () public { owner = msg.sender; }
    /* Function to recover the funds on the contract */
    function kill() public { if (msg.sender == owner) selfdestruct(owner); }
}

contract KlaytnGreeter is Mortal {
    /* Define variable greeting of the type string */
    string greeting;
    /* This runs once when the contract is created */
    constructor (string memory _greeting) public {
        greeting = _greeting;
    }
    /* Main function */
    function greet() public view returns (string memory) {
        return greeting;
    }
}
```

## Triển khai hợp đồng KlaytnGreeter bằng Remix Online IDE <a href="#deploying-klaytngreeter-using-klaytn-ide" id="deploying-klaytngreeter-using-klaytn-ide"></a>

* Vui lòng truy cập [Klaytn Plugin for Remix](https://ide.klaytn.foundation) và tạo hợp đồng `KlaytnGreeter`. Mã nguồn hoàn chỉnh được cung cấp trên đây.
* Chuẩn bị tài khoản của bạn để triển khai hợp đồng.
  * Nếu bạn chưa có tài khoản, hãy tạo một tài khoản tại <https://baobab.wallet.klaytn.foundation/create> hoặc \[<https://toolkit.klaytn.foundation/tài> khoản/tài khoảnKeyLegacy]\(<https://toolkit.klaytn.foundation/tài> khoản/tài khoảnKeyLegacy).
  * Nhận một số KLAY thử nghiệm từ faucet - <https://baobab.wallet.klaytn.foundation/faucet>
* Triển khai hợp đồng bằng tham số ban đầu, một thông báo chào mừng.
* Sau khi triển khai, bạn có thể gọi `greet` từ IDE.

## Tài liệu tham khảo <a href="#references" id="references"></a>

Để biết thông tin chi tiết về việc triển khai hợp đồng và hướng dẫn sử dụng Remix Online IDE, vui lòng tham khảo các tài liệu sau đây.

* [Remix Online IDE](/content/smart-contract/ide-and-tools#klaytn-ide)
* [Truffle](/content/smart-contract/ide-and-tools#truffle)
* [Hướng dẫn triển khai](/content/smart-contract/deploy-guide)


# ERC-20

## Giới thiệu <a href="#introduction" id="introduction"></a>

Hướng dẫn này giúp bạn tạo một ví dụ về token tương thích với ERC-20, tuân thủ các [Tiêu chuẩn token Klaytn](/content/smart-contract/token-standard), đặc biệt là [Tiêu chuẩn token có thể thay thế (ERC-20)](/content/smart-contract/token-standard#fungible-token-standard-kip-7).

[Tiêu chuẩn token ERC-20](https://eips.ethereum.org/EIPS/eip-20) xác định hai sự kiện và 9 phương pháp (bao gồm 3 phương pháp tùy chọn) như sau. Các token tương thích với ERC-20 là các hợp đồng token triển khai giao diện sau đây.

```
function name() public view returns (string) //optional
function symbol() public view returns (string) //optional
function decimals() public view returns (uint8) //optional
function totalSupply() public view returns (uint256)
function balanceOf(address _owner) public view returns (uint256 balance)
function transfer(address _to, uint256 _value) public returns (bool success)
function transferFrom(address _from, address _to, uint256 _value) public returns (bool success)
function approve(address _spender, uint256 _value) public returns (bool success)
function allowance(address _owner, address _spender) public view returns (uint256 remaining)

event Transfer(address indexed _from, address indexed _to, uint256 _value)
event Approval(address indexed _owner, address indexed _spender, uint256 _value)
```

Dựa trên giao diện trên đây, các nhà phát triển có thể tùy chỉnh token bằng cách thêm các tính năng và logic mới và triển khai trên mạng lưới Klaytn. Để biết thêm thông tin, hãy tham khảo [tài liệu ERC-20](https://eips.ethereum.org/EIPS/eip-20) chính thức.

Trong hướng dẫn này, bạn sẽ triển khai `MyERC20.sol`, một token tương thích với ERC-20. Token này sẽ phát hành một số lượng token định trước và gửi tất cả các token đó cho chủ sở hữu hợp đồng khi triển khai.

`MyERC20.sol` được dựa trên việc triển khai ERC20 của OpenZeppelin. Phần lớn mã trong hướng dẫn này được phân nhánh từ [OpenZeppelin 2.3](https://github.com/OpenZeppelin/openzeppelin-solidity/releases/tag/v2.3.0) và các tập tin Solidity sau được sử dụng để triển khai `MyERC20.sol`.

* <https://github.com/OpenZeppelin/openzeppelin-solidity/blob/v2.3.0/contracts/token/ERC20/IERC20.sol>
* <https://github.com/OpenZeppelin/openzeppelin-solidity/blob/v2.3.0/contracts/token/ERC20/ERC20.sol>
* <https://github.com/OpenZeppelin/openzeppelin-solidity/blob/v2.3.0/contracts/token/ERC20/ERC20Detailed.sol>
* <https://github.com/OpenZeppelin/openzeppelin-solidity/blob/v2.3.0/contracts/math/SafeMath.sol>

Phần còn lại của hướng dẫn được sắp xếp như sau.

* [1. Soạn hợp đồng thông minh ERC-20](/content/smart-contract/sample-contracts/erc-20/1-erc20)
  * 1.1 Cấu trúc tổng quan của mã `MyERC20` với toàn bộ mã `MyERC20`
  * 1.2 Tìm hiểu một số hàm quan trọng
* [2. Triển khai hợp đồng thông minh](/content/smart-contract/sample-contracts/erc-20/2-erc20)
  * 2.1 Triển khai hợp đồng thông minh bằng Klaytn IDE
  * 2.2 Triển khai hợp đồng thông minh bằng truffle
* [3. Tương tác giữa token ERC-20 và ví Klaytn](/content/smart-contract/sample-contracts/erc-20/3-erc20)


# 1. Soạn hợp đồng thông minh ERC-20

## 1.1 Cấu trúc tổng thể của MyERC20 <a href="#id-1-1-overall-structure-of-myerc20" id="id-1-1-overall-structure-of-myerc20"></a>

Dưới đây là mã nguồn đầy đủ của tập tin `MyERC20.sol`. Trong lần triển khai này, hàm `constructor` gọi `_mint` để tạo một số lượng token định trước khi triển khai hợp đồng.

```
pragma solidity ^0.5.0;

/**
 * @dev Giao diện của chuẩn ERC20 theo định nghĩa trong EIP. Không chứa
 * các hàm tùy chọn; xem `ERC20Detailed` để truy cập.
 */
interface IERC20 {
    function totalSupply() external view returns (uint256);

    function balanceOf(address tài khoản) external view returns (uint256);

    function transfer(address recipient, uint256 amount) external returns (bool);

    function allowance(address owner, address spender) external view returns (uint256);

    function approve(address spender, uint256 amount) external returns (bool);

    function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);

    event Transfer(address indexed from, address indexed to, uint256 value);

    event Approval(address indexed owner, address indexed spender, uint256 value);
}

library SafeMath {
    /**
     * @dev Trả lại tổng của hai số nguyên không dấu, hoàn ngược nếu có
     * tràn số.
     *
     * Tương đương với toán tử `+` trong Solidity.
     *
     * Yêu cầu:
     * - Phép cộng không được tràn số.
     */
    function add(uint256 a, uint256 b) internal pure returns (uint256) {
        uint256 c = a + b;
        require(c >= a, "SafeMath: phép cộng tràn số");

        return c;
    }

    /**
     * @dev Trả về hiệu của hai số nguyên không dấu, hoàn ngược nếu có
     * tràn số (khi kết quả là số âm).
     *
     * Tương đương với toán tử `-` trong Solidity.
     *
     * Yêu cầu:
     * - Phép trừ không được tràn số.
     */
    function sub(uint256 a, uint256 b) internal pure returns (uint256) {
        require(b <= a, "SafeMath: phép trừ tràn số");
        uint256 c = a - b;

        return c;
    }

    /**
     * @dev Trả về tích của hai số nguyên không dấu, hoàn ngược nếu có
     * tràn số.
     *
     * Tương đương với toán tử `*` trong Solidity.
     *
     * Yêu cầu:
     * - Phép nhân không được tràn số.
     */
    function mul(uint256 a, uint256 b) internal pure returns (uint256) {
        // Tối ưu hóa phí ga: cách này rẻ hơn yêu cầu 'a' thay vì 0, nhưng
        // lợi ích sẽ mất nếu 'b' cũng kiểm thử.
        // See: https://github.com/OpenZeppelin/openzeppelin-solidity/pull/522
        if (a == 0) {
            return 0;
        }

        uint256 c = a * b;
        require(c / a == b, "SafeMath: phép nhân tràn số");

        return c;
    }

    /**
     * @dev Trả về giá trị nguyên của phép chia hai số nguyên không dấu. Hoàn ngược nếu
     * chia cho 0. Kết quả được làm tròn về 0.
     *
     * Tương đương với toán tử `/` trong Solidity. Lưu ý: hàm này sử dụng một
     * mã vận hành `revert` (giữ lại toàn bộ gas còn lại) trong khi Solidity
     *  sử dụng một mã vận hành không hợp lệ để hoàn ngược (tiêu thụ toàn bộ gas còn lại).
     *
     * Yêu cầu:
     * - Số chia không được bằng 0.
     */
    function div(uint256 a, uint256 b) internal pure returns (uint256) {
        // Solidity chỉ tự động kiểm tra khi chia cho 0
        require(b > 0, "SafeMath: số chia bằng 0");
        uint256 c = a / b;
        // assert(a == b * c + a % b); // Không có trường hợp nào mà điều này không đúng

        return c;
    }

    /**
     * @dev Trả về phần dư của phép chia hai số nguyên không dấu. (unsigned integer modulo),
     * Hoàn ngược khi chia cho 0.
     *
     * Tương đương với toán tử `%` trong Solidity. Hàm này sử dụng một
     * mã vận hành `revert` (giữ lại toàn bộ gas còn lại) trong khi Solidity
     *  sử dụng một mã vận hành không hợp lệ để hoàn ngược (tiêu thụ toàn bộ gas còn lại).
     *
     * Yêu cầu:
     * - Số chia không được bằng 0.
     */
    function mod(uint256 a, uint256 b) internal pure returns (uint256) {
        require(b != 0, "SafeMath: số chia bằng 0");
        return a % b;
    }
}

/**
 * @dev Triển khai giao diện `IERC20`.
 *
 * Lần triển khai này không phụ thuộc vào cách tạo token. Điều này có nghĩa là
 * cơ chế cung cấp phải được thêm vào một hợp đồng phái sinh thông qua `_mint`.
 * Để biết cơ chế tổng quát, xem `ERC20Mintable`.
 *
 * *Để biết thêm chi tiết, hãy xem hướng dẫn của chúng tôi [Cách triển khai
 * cơ chế cung cấp](https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226).*
 *
 * Chúng tôi đã tuân thủ các hướng dẫn tổng quát của OpenZeppelin: các hàm hoàn ngược thay vì
 * trả về `false` khi thất bại. Tuy nhiên, hành vi này khá phổ biến
 * và không xung đột với các kỳ vọng của ứng dụng ERC20.
 *
 * Ngoài ra, sự kiện `Approval` được kích hoạt khi gọi `transferFrom`.
 * Điều này cho phép ứng dụng xây dựng lại ủy quyền cho tất cả các tài khoản
 * chỉ bằng cách nghe các sự kiện này. Các lần triển khai khác của EIP có thể không phát ra
 * các sự kiện này vì không yêu cầu trong tiêu chuẩn kỹ thuật.
 *
 * Cuối cùng, hai hàm không chuẩn `decreaseAllowance` và `increaseAllowance`
 * đã được thêm vào để giảm thiểu các vấn đề phổ biến liên quan đến việc
 * thiết lập ủy quyền. Xem `IERC20.approve`.
 */
contract MyERC20 is IERC20 {
    using SafeMath for uint256;

    mapping (address => uint256) private _balances;

    mapping (address => mapping (address => uint256)) private _allowances;

    // NOTE Start of https://github.com/OpenZeppelin/openzeppelin-solidity/blob/v2.3.0/contracts/token/ERC20/ERC20Detailed.sol
    string private _name;
    string private _symbol;
    uint8 private _decimals;

    constructor (string memory name, string memory symbol, uint8 decimals) public {
        _name = name;
        _symbol = symbol;
        _decimals = decimals;

        _mint(msg.sender, 100000 * 10 ** uint256(decimals)); // CAUTION!
    }

    /**
     * @dev Trả về tên của token.
     */
    function name() public view returns (string memory) {
        return _name;
    }

    /**
     * @dev Trả về ký hiệu của token, thường là phiên bản ngắn gọn của
     * tên.
     */
    function symbol() public view returns (string memory) {
        return _symbol;
    }

    /**
     * @dev Trả về số chữ số thập phân được sử dụng để hiển thị cho người dùng.
     * Ví dụ, nếu `decimals` là `2`, số dư của token `505` sẽ
     * được hiển thị cho người dùng dưới dạng `5,05` (`505 / 10 ** 2`).
     *
     * Các token thường chọn giá trị 18, tương tự mối quan hệ giữa
     * Ether và Wei.
     *
     * > Lưu ý rằng thông tin này chỉ được sử dụng cho _mục đích_ hiển thị: nó
     * không ảnh hưởng đến bất kỳ phép tính nào của hợp đồng, bao gồm
     * `IERC20.balanceOf` và `IERC20.transfer`.
     */
    function decimals() public view returns (uint8) {
        return _decimals;
    }
    // NOTE End of https://github.com/OpenZeppelin/openzeppelin-solidity/blob/v2.3.0/contracts/token/ERC20/ERC20Detailed.sol

    uint256 private _totalSupply;

    /**
     * @dev Xem `IERC20.totalSupply`.
     */
    function totalSupply() public view returns (uint256) {
        return _totalSupply;
    }

    /**
     * @dev Xem `IERC20.balanceOf`.
     */
    function balanceOf(address tài khoản) public view returns (uint256) {
        return _balances[tài khoản];
    }

    /**
     * @dev Xem `IERC20.transfer`.
     *
     * Yêu cầu:
     *
     * - `recipient` không được là địa chỉ không hợp lệ.
     * - người gọi phải có số dư tối thiểu là `amount`.
     */
    function transfer(address recipient, uint256 amount) public returns (bool) {
        _transfer(msg.sender, recipient, amount);
        return true;
    }

    /**
     * @dev Xem `IERC20.allowance`.
     */
    function allowance(address owner, address spender) public view returns (uint256) {
        return _allowances[owner][spender];
    }

    /**
     * @dev Xem `IERC20.approve`.
     *
     * Yêu cầu:
     *
     * - `spender` không được là địa chỉ không hợp lệ.
     */
    function approve(address spender, uint256 value) public returns (bool) {
        _approve(msg.sender, spender, value);
        return true;
    }

    /**
     * @dev Xem `IERC20.transferFrom`.
     *
     * Kích hoạt sự kiện `Approval` để chỉ thị phân quyền cập nhật. Điều này không
     * bắt buộc theo EIP. Xem phần lưu ý ở đầu mục ERC20`;
     *
     * Yêu cầu:
     * - `sender` và `recipient` không được là địa chỉ không hợp lệ.
     * - `sender` phải có số dư tối thiểu là `value`.
     * - Người gọi phải có phân quyền cho token của `sender` ít nhất là
     * `amount`.
     */
    function transferFrom(address sender, address recipient, uint256 amount) public returns (bool) {
        _transfer(sender, recipient, amount);
        _approve(sender, msg.sender, _allowances[sender][msg.sender].sub(amount));
        return true;
    }

    /**
     * @dev Tăng không đáng kể tỷ lệ phân quyền được người gọi cấp cho `spender`.
     *
     * Đây là một phương pháp thay thế cho `approve` có thể được sử dụng để giảm thiểu
     * các vấn đề được mô tả trong `IERC20.approve`.
     *
     * Kích hoạt sự kiện `Approval` để chỉ thị phân quyền cập nhật.
     *
     * Yêu cầu:
     *
     * - `spender` không được là địa chỉ không hợp lệ.
     */
    function increaseAllowance(address spender, uint256 addedValue) public returns (bool) {
        _approve(msg.sender, spender, _allowances[msg.sender][spender].add(addedValue));
        return true;
    }

    /**
     * @dev Tăng tỷ lệ phân quyền được người gọi cấp cho `spender` một cách an toàn.
     *
     * Đây là một phương pháp thay thế cho `approve` có thể được sử dụng để giảm thiểu
     * các vấn đề được mô tả trong `IERC20.approve`.
     *
     * Kích hoạt sự kiện `Approval` để chỉ thị phân quyền cập nhật.
     *
     * Yêu cầu:
     *
     * - `spender` không được là địa chỉ không hợp lệ.
     * - `spender` phải có giá trị phân quyền cho người gọi ít nhất là
     * `subtractedValue`.
     */
    function decreaseAllowance(address spender, uint256 subtractedValue) public returns (bool) {
        _approve(msg.sender, spender, _allowances[msg.sender][spender].sub(subtractedValue));
        return true;
    }

    /**
     * @dev Di chuyển `amount` token từ `sender` sang `recipient`.
     *
     * Đây là hàm nội bộ tương đương với `transfer` và có thể được dùng để
     * ví dụ, triển khai phí tự động cho token, các cơ chế xử phạt, v.v.
     *
     * Kích hoạt sự kiện `Transfer`.
     *
     * Yêu cầu:
     *
     * - `sender` không được là địa chỉ không hợp lệ.
     * - `recipient` không được là địa chỉ không hợp lệ.
     * - `sender` phải có số dư tối thiểu là `amount`.
     */
    function _transfer(address sender, address recipient, uint256 amount) internal {
        require(sender != address(0), "ERC20: chuyển từ địa chỉ không hợp lệ");
        require(recipient != address(0), "ERC20: chuyển đến địa chỉ không hợp lệ");

        _balances[sender] = _balances[sender].sub(amount);
        _balances[recipient] = _balances[recipient].add(amount);
        emit Transfer(sender, recipient, amount);
    }

    /** @dev Tạo `amount` token và gán chúng cho `tài khoản`, tăng
     * tổng cung.
     *
     * Kích hoạt sự kiện `Transfer` với `from` được đặt thành địa chỉ không hợp lệ.
     *
     * Yêu cầu:
     *
     * - `to` không được là địa chỉ không hợp lệ.
     */
    function _mint(address tài khoản, uint256 amount) internal {
        require(tài khoản != address(0), "ERC20: tạo đến địa chỉ không hợp lệ");

        _totalSupply = _totalSupply.add(amount);
        _balances[tài khoản] = _balances[tài khoản].add(amount);
        emit Transfer(address(0), tài khoản, amount);
    }

     /**
     * @dev Hủy `amount` token từ `tài khoản`, giảm
     * tổng cung.
     *
     * Kích hoạt sự kiện `Transfer` với `to` được thiết lập thành địa chỉ không hợp lệ.
     *
     * Yêu cầu:
     *
     * - `tài khoản` không được là địa chỉ không hợp lệ.
     * - `tài khoản` phải có ít nhất `amount` token.
     */
    function _burn(address tài khoản, uint256 value) internal {
        require(tài khoản != address(0), "ERC20: đốt từ địa chỉ không hợp lệ");

    _balances[tài khoản] = _balances[tài khoản].sub(value);
        _totalSupply = _totalSupply.sub(value);
        emit Transfer(tài khoản, address(0), value);
    }

    /**
     * @dev Thiết lập `amount` làm giá trị phân quyền của `spender` cho token của `owner`.
     *
     * Đây là hàm nội bộ tương đương với `approve` và có thể được dùng để
     * ví dụ, thiết lập cơ chế phân quyền tự động cho các hệ thống phụ nhất định, v.v.
     *
     * Kích hoạt sự kiện `Approval`.
     *
     * Yêu cầu:
     *
     * - `owner` không được là địa chỉ không hợp lệ.
     * - `spender` không được là địa chỉ không hợp lệ.
     */
    function _approve(address owner, address spender, uint256 value) internal {
        require(owner != address(0), "ERC20: duyệt đến địa chỉ không hợp lệ");
        require(spender != address(0), "ERC20: duyệt đến địa chỉ không hợp lệ");

        _allowances[owner][spender] = value;
        emit Approval(owner, spender, value);
    }

    /**
     * @dev Hủy `amount` token từ `tài khoản`.`amount` sau đó được trừ khỏi
     * giá trị phân quyền của người gọi.
     *
     * Xem `_burn` và `_approve`.
     */
    function _burnFrom(address tài khoản, uint256 amount) internal {
        _burn(tài khoản, amount);
        _approve(tài khoản, msg.sender, _allowances[tài khoản][msg.sender].sub(amount));
    }
}
```

`MyERC20.sol` bao gồm một giao diện `IERC20`, một thư viện `SafeMath` và một hợp đồng `MyERC20`, triển khai giao diện `IERC20`.

* Giao diện `IERC20` xác định giao diện bắt buộc được mô tả trong [tiêu chuẩn kỹ thuật của ERC-20](https://eips.ethereum.org/EIPS/eip-20).
* Thư viện `SafeMath` xác định các lớp bọc (wrapper) cho các phép toán số học trong Solidity, kèm theo kiểm tra tràn số để đảm bảo tính toàn vẹn của phép tính với kiểu `uint256` trong Solidity.
* `MyERC20` triển khai các giao diện `IERC20` và cũng xác định ba phương pháp tùy chọn được mô tả trong [tiêu chuẩn kỹ thuật của ERC-20](https://eips.ethereum.org/EIPS/eip-20).
  * Ngoài ERC20, hàm `constructor` cũng được xác định và hàm tạo này được sử dụng để đặt tên và ký hiệu cho một token ERC20 mới và để tạo một số lượng token định trước. `constructor` được gọi một lần trong lần triển khai đầu tiên.

## 1.2 Tìm hiểu một số phương pháp quan trọng <a href="#id-1-2-take-a-look-at-important-methods" id="id-1-2-take-a-look-at-important-methods"></a>

Hãy tìm hiểu chi tiết một số phương pháp quan trọng.

### (1) `function balanceOf(address tài khoản) external view returns (uint256);` <a href="#id-1-function-balanceof-address-account-external-view-returns-uint256" id="id-1-function-balanceof-address-account-external-view-returns-uint256"></a>

`balanceOf` là phương pháp bắt buộc của ERC-20. `balanceOf` trả về số dư của địa chỉ đã cho.

```
    function balanceOf(address tài khoản) public view returns (uint256) {
        return _balances[tài khoản];
    }
```

`balanceOf` chỉ trả về giá trị khóa `tài khoản` được lưu trong `_balances` là kiểu `mapping (address => uint256)` như dưới đây.

```
    mapping (address => uint256) private _balances;
```

Nếu không có khóa `tài khoản` trong `_balances` thì giá trị trả về chỉ là `0`.

### (2) `function transfer(address recipient, uint256 amount) external returns (bool);` <a href="#id-2-function-transfer-address-recipient-uint256-amount-external-returns-bool" id="id-2-function-transfer-address-recipient-uint256-amount-external-returns-bool"></a>

`transfer` là phương pháp bắt buộc của ERC-20. `transfer` chuyển `amount` token cho `recipient` và hàm MUST kích hoạt sự kiện `Transfer`. Hàm SHOULD thông báo lỗi ngoại lệ nếu số dư tài khoản của người gọi thông báo không có đủ token để chi tiêu.

`transfer` chỉ gọi phương pháp nội bộ `_transfer` thực hiện việc chuyển giao thực tế và tạo sự kiện như sau.

```
    function transfer(address recipient, uint256 amount) public returns (bool) {
        _transfer(msg.sender, recipient, amount);
        return true;
    }
```

`_transfer` triển khai hành vi thực tế của phương pháp `transfer` trong tiêu chuẩn ERC-20.

Ngoài ra, hàm này ngăn chặn việc gửi token từ hoặc đến địa chỉ không hợp lệ bằng cách sử dụng lệnh `require` như sau.

```
    function _transfer(address sender, address recipient, uint256 amount) internal {
        require(sender != address(0), "ERC20: transfer from the zero address");
        require(recipient != address(0), "ERC20: transfer to the zero address");

        _balances[sender] = _balances[sender].sub(amount);
        _balances[recipient] = _balances[recipient].add(amount);
        emit Transfer(sender, recipient, amount);
    }
```

### (3) `function approve(address spender, uint256 amount) external returns (bool);` <a href="#id-3-function-approve-address-spender-uint256-amount-external-returns-bool" id="id-3-function-approve-address-spender-uint256-amount-external-returns-bool"></a>

`approve` là phương pháp bắt buộc của ERC-20. Hàm `approve` cho phép `spender` được rút tiền nhiều lần từ tài khoản của bạn, với giá trị lên đến `amount`. Nếu hàm này được gọi nhiều lần, hàm sẽ đơn giản là đặt lại giới hạn ủy quyền với giá trị `amount`.

`approve` gọi phương pháp nội bộ `_approve` để thực hiện hành vi `approve` thực tế. `msg.sender` được truyền dưới dạng tài khoản `owner`.

```
    function approve(address spender, uint256 value) public returns (bool) {
        _approve(msg.sender, spender, value);
        return true;
    }

    function _approve(address owner, address spender, uint256 value) internal {
        require(owner != address(0), "ERC20: duyệt từ địa chỉ không hợp lệ");
        require(spender != address(0), "ERC20: duyệt đến địa chỉ không hợp lệ");

        _allowances[owner][spender] = value;
        emit Approval(owner, spender, value);
    }
```

Hàm `_approve` cập nhật `_allowances`, đây là một từ điển 2 chiều giữ `value` được ủy quyền cho `spender` từ `address` cụ thể.

```
    mapping (address => mapping (address => uint256)) private _allowances;
```

### (4) `function _mint(address tài khoản, uint256 amount) internal` <a href="#id-4-function-_mint-address-account-uint256-amount-internal" id="id-4-function-_mint-address-account-uint256-amount-internal"></a>

`_mint` không phải là một phần của tiêu chuẩn ERC-20. Tuy nhiên, chúng tôi cần một cách để tạo ra các token ERC-20 mới và đã áp dụng `_mint` để tạo ra các token mới trong lần triển khai này như sau.

```
    function _mint(address tài khoản, uint256 amount) internal {
        require(tài khoản != address(0), "ERC20: mint to the zero address");

        _totalSupply = _totalSupply.add(amount);
        _balances[tài khoản] = _balances[tài khoản].add(amount);
        emit Transfer(address(0), tài khoản, amount);
    }
```

`_mint` là một phương pháp nội bộ và có thể được gọi bên trong hợp đồng này.

Trong tiêu chuẩn `MyERC20.sol`, `_mint` được gọi chỉ một lần từ `constructor` khi triển khai hợp đồng thông minh để tạo một số lượng token định trước.

Nếu bạn muốn phát hành thêm token sau khi triển khai hợp đồng thông minh, bạn phải giới thiệu một phương pháp công khai mới như `mint`. Cần CẨN TRỌNG khi triển khai phương pháp này vì chỉ những người dùng được ủy quyền mới có thể tạo token.

Vui lòng xem ví dụ [ERC20Mintable.sol](https://github.com/OpenZeppelin/openzeppelin-solidity/blob/v2.3.0/contracts/token/ERC20/ERC20Mintable.sol) của OpenZeppelin để biết thêm chi tiết.


# 2. Triển khai hợp đồng thông minh

Bạn có thể sử dụng Remix Online IDE hoặc Truffle để triển khai hợp đồng thông minh `MyERC20`.

## 2.1 Triển khai hợp đồng thông minh bằng Remix Online IDE <a href="#id-2-1-deploying-smart-contract-using-klaytn-ide" id="id-2-1-deploying-smart-contract-using-klaytn-ide"></a>

* Vui lòng truy cập [Klaytn Plugin for Remix](https://ide.klaytn.foundation) và tạo hợp đồng `MyERC20`. Toàn bộ mã nguồn đã được cung cấp tại mục [Soạn hợp đồng thông minh ERC-20](/content/smart-contract/sample-contracts/erc-20/1-erc20).
* Chuẩn bị tài khoản của bạn để triển khai hợp đồng.
  * Nếu bạn chưa có tài khoản, hãy tạo một tài khoản tại <https://baobab.wallet.klaytn.foundation/create> hoặc \[<https://toolkit.klaytn.foundation/tài> khoản/tài khoảnKeyLegacy]\(<https://toolkit.klaytn.foundation/tài> khoản/tài khoảnKeyLegacy).
  * Nhận một số KLAY thử nghiệm từ faucet - <https://baobab.wallet.klaytn.foundation/faucet>
* Hãy triển khai `MyERC20.sol` với các tham số triển khai là `BAOBABTOKEN`, `BAO` và `8`.

![ERC20-1-deploy](/files/NLVyYiKgH4s6yVWtnX7H)

Sau khi triển khai, bạn có thể gọi hàm `balanceOf` với tài khoản của bạn đã được dùng để triển khai hợp đồng. Bạn sẽ thấy có `10000000000000` token có sẵn trong tài khoản của bạn như dưới đây. Vì bạn đã đặt `decimal` là `8` khi triển khai hợp đồng ở trên, nó đã tạo ra một số cố định là `100000` token trong hàm khởi tạo, với mỗi token có giá trị thập phân là `10^8`. Phương thức `totalSupply` sẽ trả về tổng cung của các token đã tạo, cũng bằng `10000000000000`.

![ERC20-2-owner-token](/files/K7sx7Vc4ooq1mFmGpdIH)

`MyERC20` hiện đang hoạt động !

## 2.2 Triển khai hợp đồng thông minh bằng truffle <a href="#id-2-2-deploying-smart-contract-using-truffle" id="id-2-2-deploying-smart-contract-using-truffle"></a>

Bạn nên cài đặt xong [node.js](https://nodejs.org/) trong môi trường của mình. Hãy xem [Hướng dẫn cài đặt Node.js qua trình quản lý gói](https://nodejs.org/en/download/package-manager/) để cài đặt node.js bằng trình quản lý gói trong các môi trường khác nhau.

```
$ mkdir klaytn
$ cd klaytn
$ npm init # initialize npm at the erc20token directory
$ npm install truffle@4.1.15
$ npm install caver-js@latest # installing caver-js
$ ln -s node_modules/truffle/build/cli.bundled.js truffle
$ export PATH=`pwd`:$PATH
```

Giờ đây, bạn đã cài đặt truffle và caver-js, hai công cụ cần thiết để triển khai hợp đồng thông minh.

Hãy chuẩn bị `truffle` và một hợp đồng thông minh `MyERC20.sol`.

```
$ mkdir myerc20
$ cd myerc20
$ truffle init
```

Giờ bạn sẽ có các cấu trúc thư mục như sau.

```
.
├── contracts
│   ├── Migrations.sol
├── migrations
│   └── 1_initial_migration.js
└── truffle-config.js
```

Giờ hãy soạn `MyERC20.sol` và đặt nó vào thư mục `contracts`.

Bạn cũng cần chỉnh sửa tập tin `1_initial_migration.js` như sau để triển khai hợp đồng `MyERC20` với các tham số ban đầu là `BAOBABTOKEN`, `BAO` và `8`. Tên của đồng token được đặt là `BAOBABTOKEN` và ký hiệu token là `BAO`. Token có giá trị thập phân là `10^8`. Lưu ý rằng ví dụ, khi bạn truy vấn `totalSupply` của `BAOBABTOKEN`, nó sẽ trả về `10^13`, không phải `10^5`, vì Solidity không hỗ trợ số thực dấu phẩy động, số lượng token luôn được biểu diễn dưới dạng số tự nhiên ở đơn vị nhỏ nhất.

```javascript
const Migrations = artifacts.require("./Migrations.sol");
const MyERC20 = artifacts.require("./MyERC20.sol");
module.exports = function(deployer) {
  deployer.deploy(Migrations);
  deployer.deploy(MyERC20, 'BAOBABTOKEN', 'BAO', 8);
};
```

Bạn cũng phải chỉnh sửa tập tin `truffle-config.js` như dưới đây để triển khai hợp đồng thông minh lên mạng lưới Klaytn. Bước này giống như bước được mô tả trong [Triển khai Hợp đồng thông minh bằng Truffle](/content/getting-started/quick-start/deploy-a-smart-contract#deploying-a-smart-contract-using-truffle).

```
// truffle-config.js
module.exports = {
    networks: {
        baobab: {
            host: '127.0.0.1',
            port: 8551,
            from: '0xabcdabcdabcdabcdabcdabcdabcdabcdabcdabcd', // nhập địa chỉ hợp đồng của bạn
            network_id: '1001', // id mạng Baobab
            gas: 20000000, // giới hạn gas của giao dịch
            gasPrice: 250000000000, // gasPrice của Baobab là 250 ston
        },
    },
    compilers: {
      solc: {
        version: "0.5.12"    // Chỉ định phiên bản trình biên dịch là 0.5.12
      }
  }
};
```

Giờ bạn đã sẵn sàng và có thể triển khai `MyERC20.sol` như dưới đây.

```
$ truffle deploy --network baobab --reset
Compiling ./contracts/MyERC20.sol...
Soạn các tập tin artifact trong thư mục ./build/contracts

Sử dụng mạng lưới 'baobab'.

Running migration: 1_initial_migration.js
  Replacing Migrations...
  ... 0x5a947f076f4570dff8ff18b1ae3557e27dd69c92ce38a3c97fad8f5355914066
  Migrations: 0x0d737e9865e5fc4c1ff53744fd2c13c52a44b9bc
  Deploying MyERC20...
  ... 0x1571e80552dab1d67260e8914e06d9b16ccae16fb698c750f6a09aab12517bc1
  MyERC20: 0xc4c8257ED9B4eB6422fDe29B1eCe5Ce301e637e1
Lưu quá trình di chuyển thành công lên mạng...
  ... 0x5b984b3f79c425d80470a96d5badb857fc05e7f31d94423044ae3119c639aa77
Lưu các tập tin artifact...
```

Nó hiển thị hàm băm giao dịch để triển khai hợp đồng `MyERC20` là `0x1571e80552dab1d67260e8914e06d9b16ccae16fb698c750f6a09aab12517bc1` và địa chỉ của `MyERC20` là `0xc4c8257ED9B4eB6422fDe29B1eCe5Ce301e637e1`.

Hiện `MyERC20` đang hoạt động !


# 3. Tương tác với token ERC-20 từ Ví Klaytn

Bạn có thể sử dụng [Ví Baobab Klaytn](https://baobab.wallet.klaytn.foundation) để truy vấn số dư và chuyển `BAOBABTOKEN` tương thích với ERC-20 mà bạn vừa triển khai.

Bạn có thể thêm token tương thích với ERC-20 vào ví của bạn bằng cách sử dụng địa chỉ của hợp đồng `MyERC20` đã triển khai như dưới đây.

![ERC20-3-Add\_token](/files/RjhvrJhyC89pS20qpHmh)

Sau khi thêm token ERC-20 vào ứng dụng ví, số dư `BAOBABTOKEN` của bạn sẽ được hiển thị cùng với số dư KLAY như sau. Bạn có thể thấy có `100000` token `BAO` trong tài khoản.

![ERC20-4-wallet-token](/files/FNrRBxBHFdCOIwTRdUJJ)


# ERC-721

## Giới thiệu <a href="#introduction" id="introduction"></a>

Hướng dẫn này giúp bạn tạo một ví dụ về token tương thích với ERC-721, tuân thủ các [Tiêu chuẩn token Klaytn](/content/smart-contract/token-standard), đặc biệt là [Tiêu chuẩn token không thể thay thế (ERC-721)](/content/smart-contract/token-standard#non-fungible-token-standard-kip-17).

[Tiêu chuẩn token không thể thay thế ERC-721](https://eips.ethereum.org/EIPS/eip-721) xác định ba sự kiện và 10 phương pháp như sau. Hàm `supportsInterface` của ERC-721 được kế thừa từ tiêu chuẩn [ERC-165 Standard Interface Detection](https://eips.ethereum.org/EIPS/eip-165) và ERC-165 là một phần của ERC-721. Các token tương thích với ERC-721 là các hợp đồng token triển khai các giao diện ERC-721 và ERC-165 như sau.

```solidity
event Transfer(address indexed _from, address indexed _to, uint256 indexed _tokenId);
event Approval(address indexed _owner, address indexed _approved, uint256 indexed _tokenId);
event ApprovalForAll(address indexed _owner, address indexed _operator, bool _approved);

function balanceOf(address _owner) external view returns (uint256);
function ownerOf(uint256 _tokenId) external view returns (address);
function safeTransferFrom(address _from, address _to, uint256 _tokenId, bytes data) external payable;
function safeTransferFrom(address _from, address _to, uint256 _tokenId) external payable;
function transferFrom(address _from, address _to, uint256 _tokenId) external payable;
function approve(address _approved, uint256 _tokenId) external payable;
function setApprovalForAll(address _operator, bool _approved) external;
function getApproved(uint256 _tokenId) external view returns (address);
function isApprovedForAll(address _owner, address _operator) external view returns (bool);
function supportsInterface(bytes4 interfaceID) external view returns (bool);
```

Dựa trên giao diện trên đây, các nhà phát triển có thể tùy chỉnh token bằng cách thêm các tính năng và logic mới và triển khai trên mạng lưới Klaytn. Để biết thêm thông tin, hãy tham khảo [tiêu chuẩn kỹ thuật của ERC-721](https://eips.ethereum.org/EIPS/eip-721) chính thức.

Trong hướng dẫn này, bạn sẽ triển khai `MyERC721Card.sol`, sẽ triển khai một token không thể thay thế theo kiểu thẻ, tức là `MyERC721Card`, một token ERC-721. Mỗi `MyERC721Card` có tên và cấp độ, ví dụ: "King" với cấp độ 1, "Queen" với cấp độ 1.

`MyERC721Card.sol` được dựa trên việc triển khai ERC721 của OpenZeppelin. Phần lớn mã trong hướng dẫn này được phân nhánh từ [OpenZeppelin 2.3](https://github.com/OpenZeppelin/openzeppelin-solidity/releases/tag/v2.3.0).

Phần còn lại của hướng dẫn được sắp xếp như sau.

* [1. Soạn hợp đồng thông minh ERC-721](/content/smart-contract/sample-contracts/erc-721/1-erc721)
  * 1.1 Cấu trúc tổng quan của mã `MyERC721Card` với toàn bộ mã `MyERC721Card`
  * 1.2 Tìm hiểu một số hàm quan trọng
* [2. Triển khai hợp đồng thông minh](/content/smart-contract/sample-contracts/erc-721/2-erc721)
  * 2.1 Triển khai hợp đồng thông minh bằng Remix Online IDE
  * 2.2 Triển khai hợp đồng thông minh bằng truffle


# 1. Soạn hợp đồng thông minh ERC-721

## 1.1 Cấu trúc tổng thể của MyERC721Card <a href="#id-1-1-overall-structure-of-myerc721card" id="id-1-1-overall-structure-of-myerc721card"></a>

Dưới đây là mã nguồn đầy đủ của tập tin `MyERC721Card.sol`.

```
pragma solidity ^0.5.0;

// https://github.com/OpenZeppelin/openzeppelin-solidity/blob/v2.3.0/contracts/utils/Address.sol
/**
 * @dev Tập hợp các hàm liên quan đến kiểu địa chỉ,
 */
library Address {
    /**
     * @dev Trả về giá trị đúng nếu `tài khoản` là một hợp đồng.
     *
     * Đoạn kiểm thử này không hoàn chỉnh và có thể cho kết quả sai: trong quá trình
     * thực thi hàm khởi tạo của một hợp đồng, địa chỉ của nó có thể được báo cáo
     * là không chứa hợp đồng.
     *
     * > Sẽ không an toàn khi cho rằng một địa chỉ mà hàm này trả về giá trị
     * sai là tài khoản thuộc sở hữu ngoài (EOA) và không phải là hợp đồng.
     */
    function isContract(address tài khoản) internal view returns (bool) {
        // Phương thức này dựa trên extcodesize, nó trả về giá trị 0 cho các hợp đồng
        // trong quá trình khởi tạo, vì mã chỉ được lưu trữ vào cuối
        // quá trình thực thi hàm khởi tạo.

        uint256 size;
        // solhint-disable-next-line no-inline-assembly
        assembly { size := extcodesize(tài khoản) }
        return size > 0;
    }
}

// https://github.com/OpenZeppelin/openzeppelin-solidity/blob/v2.3.0/contracts/math/SafeMath.sol
/**
 * @dev Các lớp bọc cho các phép toán số học của Solidity với
 * kiểm tra thêm về tràn số.
 *
 * Các phép toán số học trong Solidity sẽ bao bọc khi tràn số. Điều này có thể dễ dàng dẫn đến
 * lỗi, vì các nhà phát triển thường giả định rằng tràn số sẽ gây ra một lỗi,
 * đây là hành vi tiêu chuẩn trong các ngôn ngữ lập trình cao cấp.
 * `SafeMath` khôi phục lại giả thuyết này bằng cách hoàn ngược giao dịch
 * khi một phép toán tràn số xảy ra.
 *
 * Sử dụng thư viện thay vì các phép toán chưa kiểm tra sẽ loại bỏ toàn bộ
 * các loại lỗi, do đó khuyến nghị luôn sử dụng thư viện.
 */
library SafeMath {
    /**
     * @dev Trả về tổng của hai số nguyên không dấu, hoàn ngược nếu có
     * tràn số.
     *
     * Tương đương với toán tử `+` trong Solidity.
     *
     * Yêu cầu:
     * - Phép cộng không được tràn số.
     */
    function add(uint256 a, uint256 b) internal pure returns (uint256) {
        uint256 c = a + b;
        require(c >= a, "SafeMath: phép cộng tràn số");

        return c;
    }

    /**
     * @dev Trả về hiệu của hai số nguyên không dấu, hoàn ngược nếu có
     * tràn số (khi kết quả âm).
     *
     * Tương đương với toán tử `-` trong Solidity.
     *
     * Yêu cầu:
     * - Phép trừ không được tràn số.
     */
    function sub(uint256 a, uint256 b) internal pure returns (uint256) {
        require(b <= a, "SafeMath: phép trừ tràn số");
        uint256 c = a - b;

        return c;
    }

    /**
     * @dev Trả về tích của hai số nguyên không dấu, hoàn ngược nếu có
     * tràn số.
     *
     * Tương đương với toán tử `*` trong Solidity.
     *
     * Yêu cầu:
     * - Phép nhân không được tràn số.
     */
    function mul(uint256 a, uint256 b) internal pure returns (uint256) {
        // Tối ưu hóa gas: điều này tiết kiệm gas hơn so với yêu cầu 'a' không bằng không, nhưng
        // lợi ích sẽ bị mất nếu 'b' cũng được kiểm thử.
        // See: https://github.com/OpenZeppelin/openzeppelin-solidity/pull/522
        if (a == 0) {
            return 0;
        }

        uint256 c = a * b;
        require(c / a == b, "SafeMath: phép nhân tràn số");

        return c;
    }

    /**
     * @dev Trả về giá trị nguyên của phép chia hai số nguyên không dấu. Hoàn ngược nếu có
     * phép chia cho số 0. Kết quả được làm tròn về 0.
     *
     * Tương đương với toán tử `/` trong Solidity. Lưu ý: hàm này sử dụng một
     * mã vận hành `revert` (giữ lại toàn bộ gas còn lại) trong khi Solidity
     *  sử dụng một mã vận hành không hợp lệ để hoàn ngược (tiêu thụ toàn bộ gas còn lại).
     *
     * Yêu cầu:
     * - Số chia không được bằng 0.
     */
    function div(uint256 a, uint256 b) internal pure returns (uint256) {
        // Solidity chỉ tự động kiểm tra khi chia cho 0
        require(b > 0, "SafeMath: division by zero");
        uint256 c = a / b;
        // assert(a == b * c + a % b); // Không có trường hợp nào mà điều này không đúng

        return c;
    }

    /**
     * @dev Trả về phần dư của phép chia hai số nguyên không dấu. (unsigned integer modulo),
     * Hoàn ngược khi chia cho 0.
     *
     * Tương đương với toán tử `%` trong Solidity. Hàm này sử dụng một
     * mã vận hành `revert` (giữ lại toàn bộ gas còn lại) trong khi Solidity
     *  sử dụng một mã vận hành không hợp lệ để hoàn ngược (tiêu thụ toàn bộ gas còn lại).
     *
     * Yêu cầu:
     * - Số chia không được bằng 0.
     */
    function mod(uint256 a, uint256 b) internal pure returns (uint256) {
        require(b != 0, "SafeMath: số chia bằng 0");
        return a % b;
    }
}

// https://github.com/OpenZeppelin/openzeppelin-solidity/blob/v2.3.0/contracts/drafts/Counters.sol
/**
 * @title Counters
 * @author Matt Condon (@shrugs)
 * @dev Cung cấp các số đếm chỉ có thể được tăng hoặc giảm đi một đơn vị. Hàm này có thể được sử dụng, ví dụ, để theo dõi số lượng
 * phần tử trong một ánh xạ, phát hành id ERC721, hoặc đếm số id yêu cầu.
 *
 * Bao gồm `using Counters for Counters.Counter;`
 * Bởi vì không thể làm tràn một số nguyên 256 bit với giá trị gia tăng một đơn vị, `increment` có thể bỏ qua kiểm tra tràn số SafeMath,
 * do đó giúp tiết kiệm gas. Tuy nhiên, điều này giả định việc sử dụng chính xác, trong đó giá trị `_value` gốc không bao giờ
 * được truy cập trực tiếp.
 */
library Counters {
    using SafeMath for uint256;

    struct Counter {
        // Người dùng của thư viện không bao giờ được truy cập trực tiếp biến này: tương tác phải được giới hạn ở
        // các hàm của thư viện. Kể từ Solidity v0.5.2, không thể thực thi hàm này, mặc dù có đề xuất bổ sung
        // tính năng này: xem https://github.com/ethereum/solidity/issues/4637
        uint256 _value; // default: 0
    }

    function current(Counter storage counter) internal view returns (uint256) {
        return counter._value;
    }

    function increment(Counter storage counter) internal {
        counter._value += 1;
    }

    function decrement(Counter storage counter) internal {
        counter._value = counter._value.sub(1);
    }
}

/**
 * @dev Giao diện của tiêu chuẩn ERC165, như được xác định trong
 * [EIP](https://eips.ethereum.org/EIPS/eip-165).
 *
 * Người triển khai có thể tuyên bố hỗ trợ giao diện của hợp đồng, sau đó giao diện đó
 * có thể được truy vấn bởi người khác (`ERC165Checker`).
 *
 * Đối với việc triển khai, xem `ERC165`.
 */
interface IERC165 {
    /**
     * @dev Trả về giá trị đúng nếu hợp đồng này triển khai giao diện được xác định bởi
     * `interfaceId`. Xem phần tương ứng
     * [EIP section](https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified)
     * để tìm hiểu thêm về cách tạo các id này.
     *
     * Lệnh gọi hàm này phải sử dụng dưới 30 000 gas.
     */
    function supportsInterface(bytes4 interfaceId) external view returns (bool);
}

/**
 * @dev Triển khai giao diện `IERC165`.
 *
 * Các hợp đồng có thể kế thừa từ hợp đồng này và gọi `_registerInterface` để tuyên bố
 * hỗ trợ cho một giao diện.
 */
contract ERC165 is IERC165 {
    /*
     * bytes4(keccak256('supportsInterface(bytes4)')) == 0x01ffc9a7
     */
    bytes4 private constant _INTERFACE_ID_ERC165 = 0x01ffc9a7;

    /**
     * @dev Ánh xạ các id giao diện cho dù có hỗ trợ giao diện đó hay không.
     */
    mapping(bytes4 => bool) private _supportedInterfaces;

    constructor () internal {
        // Các hợp đồng có được chỉ cần đăng ký hỗ trợ giao diện của chính mình,
        // chúng tôi đăng ký hỗ trợ ERC165 tại đây
        _registerInterface(_INTERFACE_ID_ERC165);
    }

    /**
     * @dev Xem `IERC165.supportsInterface`.
     *
     * Độ phức tạp thời gian O(1), đảm bảo luôn sử dụng dưới 30 000 gas.
     */
    function supportsInterface(bytes4 interfaceId) external view returns (bool) {
        return _supportedInterfaces[interfaceId];
    }

    /**
     * @dev Đăng ký hợp đồng làm hợp đồng triển khai của giao diện như xác định trong
     * `interfaceId`. Hỗ trợ giao diện ERC165 thực tế diễn ra tự động và
     * không cần đăng ký giao diện của tiêu chuẩn này.
     *
     * Xem `IERC165.supportsInterface`.
     *
     * Yêu cầu:
     *
     * - `interfaceId` không được là giao diện không hợp lệ ERC165 (`0xffffffff`).
     */
    function _registerInterface(bytes4 interfaceId) internal {
        require(interfaceId != 0xffffffff, "ERC165: id giao diện không thành công");
        _supportedInterfaces[interfaceId] = true;
    }
}

/**
 * @dev Giao diện yêu cầu của hợp đồng tuân thủ ERC721.
 */
contract IERC721 là IERC165 {
    event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);
    event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);
    event ApprovalForAll(address indexed owner, address indexed operator, bool approved);

    /**
     * @dev Trả về số lượng NFT trong tài khoản của `owner`.
     */
    function balanceOf(address owner) public view returns (uint256 balance);

    /**
     * @dev Trả về chủ sở hữu của NFT được xác định bởi `tokenId`.
     */
    function ownerOf(uint256 tokenId) public view returns (address owner);

    /**
     * @dev Chuyển một NFT cụ thể (`tokenId`) từ một tài khoản (`from`) sang
     * tài khoản khác (`to`).
     *
     * 
     *
     * Yêu cầu:
     * - `from`, `to` không được là địa chỉ không hợp lệ.
     * - `tokenId` phải thuộc sở hữu của `from`.
     * - Nếu người gọi không phải là `from`, NFT này phải được phép chuyển
     * bằng lệnh `approve` hoặc `setApproveForAll`.
     */
    function safeTransferFrom(address from, address to, uint256 tokenId) public;
    /**
     * @dev Chuyển một NFT cụ thể (`tokenId`) từ một tài khoản (`from`) sang
     * một tài khoản khác (`to`).
     *
     * Yêu cầu:
     * - Nếu người gọi không phải là `from`, NFT này phải được phê duyệt để chuyển 
     * bằng lệnh `approve` hoặc `setApproveForAll`.
     */
    function transferFrom(address from, address to, uint256 tokenId) public;
    function approve(address to, uint256 tokenId) public;
    function getApproved(uint256 tokenId) public view returns (address operator);

    function setApprovalForAll(address operator, bool _approved) public;
    function isApprovedForAll(address owner, address operator) public view returns (bool);


    function safeTransferFrom(address from, address to, uint256 tokenId, bytes memory data) public;
} 

// https://github.com/OpenZeppelin/openzeppelin-solidity/blob/v2.3.0/contracts/token/ERC721/IERC721Receiver.sol
/**
 * @title ERC721 giao diện nhận token
 * @dev Giao diện cho bất kỳ hợp đồng nào muốn hỗ trợ safeTransfers
 * từ các hợp đồng tài sản ERC721.
 */
contract IERC721Receiver {
    /**
     * @notice Xử lý việc nhận NFT
     * @dev Hợp đồng thông minh ERC721 gọi hàm này trên người nhận
     * sau một `safeTransfer`. Hàm này PHẢI trả về bộ lọc hàm,
     * nếu không người gọi sẽ hoàn tác giao dịch. Bộ lọc hàm để
     * trả về có thể được lấy bằng hàm `this.onERC721Received.selector`. Hàm
     * này CÓ THỂ throw để hoàn ngược và từ chối giao dịch chuyển.
     * Lưu ý: địa chỉ hợp đồng ERC721 luôn luôn là người gửi thông báo.
     * @param operator The address which called `safeTransferFrom` function
     * @param from The address which previously owned the token
     * @param tokenId The NFT identifier which is being transferred
     * @param data Additional data with no specified format
     * @return bytes4 `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`
     */
    function onERC721Received(address operator, address from, uint256 tokenId, bytes memory data)
    public returns (bytes4);
}

// https://github.com/OpenZeppelin/openzeppelin-solidity/blob/v2.3.0/contracts/token/ERC721/ERC721.sol
contract ERC721 is ERC165, IERC721 {
    using SafeMath for uint256;
    using Address for address;
    using Counters for Counters.Counter;

    // Equals to `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`
    // which can be also obtained as `IERC721Receiver(0).onERC721Received.selector`
    bytes4 private constant _ERC721_RECEIVED = 0x150b7a02;

    // Mapping from token ID to owner
    mapping (uint256 => address) private _tokenOwner;

    // Mapping from token ID to approved address
    mapping (uint256 => address) private _tokenApprovals;

    // Mapping from owner to number of owned token
    mapping (address => Counters.Counter) private _ownedTokensCount;

    // Mapping from owner to operator approvals
    mapping (address => mapping (address => bool)) private _operatorApprovals;

    /*
     *     bytes4(keccak256('balanceOf(address)')) == 0x70a08231
     *     bytes4(keccak256('ownerOf(uint256)')) == 0x6352211e
     *     bytes4(keccak256('approve(address,uint256)')) == 0x095ea7b3
     *     bytes4(keccak256('getApproved(uint256)')) == 0x081812fc
     *     bytes4(keccak256('setApprovalForAll(address,bool)')) == 0xa22cb465
     *     bytes4(keccak256('isApprovedForAll(address,address)')) == 0xe985e9c
     *     bytes4(keccak256('transferFrom(address,address,uint256)')) == 0x23b872dd
     *     bytes4(keccak256('safeTransferFrom(address,address,uint256)')) == 0x42842e0e
     *     bytes4(keccak256('safeTransferFrom(address,address,uint256,bytes)')) == 0xb88d4fde
     *
     *     => 0x70a08231 ^ 0x6352211e ^ 0x095ea7b3 ^ 0x081812fc ^
     *        0xa22cb465 ^ 0xe985e9c ^ 0x23b872dd ^ 0x42842e0e ^ 0xb88d4fde == 0x80ac58cd
     */
    bytes4 private constant _INTERFACE_ID_ERC721 = 0x80ac58cd;

    constructor () public {
        // register the supported interfaces to conform to ERC721 via ERC165
        _registerInterface(_INTERFACE_ID_ERC721);
    }

    /**
     * @dev Lấy số dư của địa chỉ được chỉ định.
     * @param owner address to query the balance of
     * @return uint256 representing the amount owned by the passed address
     */
    function balanceOf(address owner) public view returns (uint256) {
        require(owner != address(0), "ERC721: truy vấn số dư cho địa chỉ không hợp lệ");

        return _ownedTokensCount[owner].current();
    }

    /**
     * @dev Nhận chủ sở hữu của ID token được chỉ định.
     * @param tokenId uint256 ID của token để truy vấn chủ sở hữu của
     * @return địa chỉ hiện được đánh dấu là chủ sở hữu của ID token đã cho
     */
    function ownerOf(uint256 tokenId) public view returns (address) {
        address owner = _tokenOwner[tokenId];
        require(owner != address(0), "ERC721: truy vấn chủ sở hữu cho mã thông báo không tồn tại");

        return owner;
    }

    /**
     * @dev Phê duyệt một địa chỉ khác để chuyển ID token đã cho
     * Địa chỉ không hợp lệ cho biết không có địa chỉ đã phê duyệt.
     * Chỉ có thể có một địa chỉ được phê duyệt cho mỗi token tại một thời điểm nhất định.
     * Chỉ có thể được gọi bởi chủ sở hữu token hoặc người vận hành đã được phê duyệt.
     * @param to address to be approved for the given token ID
     * @param tokenId uint256 ID of the token to be approved
     */
    function approve(address to, uint256 tokenId) public {
        address owner = ownerOf(tokenId);
        require(to != owner, "ERC721: phê duyệt cho chủ sở hữu hiện tại");

        require(msg.sender == owner || isApprovedForAll(owner, msg.sender),
            "ERC721: approve caller is not owner nor approved for all"
        );

        _tokenApprovals[tokenId] = to;
        emit Approval(owner, to, tokenId);
    }

    /**
     * @dev Lấy địa chỉ đã phê duyệt của ID token, hoặc địa chỉ là zero nếu chưa thiết lập địa chỉ
     * Hoàn ngược nếu ID token không tồn tại.
     * @param tokenId uint256 ID of the token to query the approval of
     * @return address currently approved for the given token ID
     */
    function getApproved(uint256 tokenId) public view returns (address) {
        require(_exists(tokenId), "ERC721: truy vấn được phê duyệt cho token không tồn tại");

        return _tokenApprovals[tokenId];
    }

    /**
     * @dev Thiết lập hoặc bỏ thiết lập phê duyệt người vận hành định trước
     * Người vận hành được phép chuyển tất cả token của người gửi thay mặt cho họ.
     * @param to operator address to set the approval
     * @param approved representing the trạng thái of the approval to be set
     */
    function setApprovalForAll(address to, bool approved) public {
        require(to != msg.sender, "ERC721: phê duyệt cho người gọi");

        _operatorApprovals[msg.sender][to] = approved;
        emit ApprovalForAll(msg.sender, to, approved);
    }

    /**
     * @dev Cho biết liệu người vận hành có được chủ sở hữu định trước phê duyệt hay không.
     * @param owner owner address which you want to query the approval of
     * @param operator operator address which you want to query the approval of
     * @return bool whether the given operator is approved by the given owner
     */
    function isApprovedForAll(address owner, address operator) public view returns (bool) {
        return _operatorApprovals[owner][operator];
    }

    /**
     * @dev Chuyển quyền sở hữu của một ID token cụ thể cho một địa chỉ khác.
     * Không khuyến nghị sử dụng phương pháp này, hãy sử dụng `safeTransferFrom` trong tất cả trường hợp có thể.
     * msg.sender bắt buộc phải là chủ sở hữu, được phê duyệt hoặc người vận hành.
     * @param from current owner of the token
     * @param to address to receive the ownership of the given token ID
     * @param tokenId uint256 ID of the token to be transferred
     */
    function transferFrom(address from, address to, uint256 tokenId) public {
        //solhint-disable-next-line max-line-length
        require(_isApprovedOrOwner(msg.sender, tokenId), "ERC721: transfer caller is not owner nor approved");

        _transferFrom(from, to, tokenId);
    }

    /**
     * @dev Chuyển quyền sở hữu của ID token đã cho một cách an toàn đến một địa chỉ khác
     * Nếu địa chỉ đích là một hợp đồng, nó phải triển khai hàm `onERC721Received`,
     * được gọi khi thực hiện chuyển giao an toàn và trả về giá trị magic
     * `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`; nếu không,
     * quá trình chuyển giao sẽ bị hoàn ngược.
     * msg.sender bắt buộc phải là chủ sở hữu hoặc người vận hành được phê duyệt.
     * @param from địa chỉ hiện tại của chủ sở hữu token
     * @param to địa chỉ nhận quyền sở hữu của ID token đã cho
     * @param tokenId uint256 ID của token sẽ được chuyển quyền sở hữu
     */
    function safeTransferFrom(address from, address to, uint256 tokenId) public {
        safeTransferFrom(from, to, tokenId, "");
    }

    /**
     * @dev Chuyển quyền sở hữu của ID token đã cho một cách an toàn đến một địa chỉ khác
     * Nếu địa chỉ đích là một hợp đồng, nó phải triển khai hàm `onERC721Received`,
     * được gọi khi thực hiện chuyển giao an toàn và trả về giá trị magic
     * `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`; otherwise,
     * quá trình chuyển giao sẽ bị hoàn ngược.
     * msg.sender bắt buộc phải là chủ sở hữu hoặc người vận hành được phê duyệt.
     * @param from current owner of the token
     * @param to address to receive the ownership of the given token ID
     * @param tokenId uint256 ID of the token to be transferred
     * @param _data bytes data to send along with a safe transfer check
     */
    function safeTransferFrom(address from, address to, uint256 tokenId, bytes memory _data) public {
        transferFrom(from, to, tokenId);
        require(_checkOnERC721Received(from, to, tokenId, _data), "ERC721: transfer to non ERC721Receiver implementer");
    }

    /**
     * @dev Trả về kết quả token chỉ định có tồn tại hay không.
     * @param tokenId uint256 ID of the token to query the existence of
     * @return bool whether the token exists
     */
    function _exists(uint256 tokenId) internal view returns (bool) {
        address owner = _tokenOwner[tokenId];
        return owner != address(0);
    }

    /**
     * @dev Trả về thông tin về việc người được ủy quyền định trước có thể chuyển giao một ID token cụ thể hay không.
     * @param spender address of the spender to query
     * @param tokenId uint256 ID of the token to be transferred
     * @return bool whether the msg.sender is approved for the given token ID,
     * is an operator of the owner, or is the owner of the token
     */
    function _isApprovedOrOwner(address spender, uint256 tokenId) internal view returns (bool) {
        require(_exists(tokenId), "ERC721: truy vấn toán tử cho token không tồn tại");
        address owner = ownerOf(tokenId);
        return (spender == owner || getApproved(tokenId) == spender || isApprovedForAll(owner, spender));
    }

    /**
     * @dev Hàm nội bộ để tạo một token mới.
     * Hoàn ngược nếu ID token đã cho đã tồn tại.
     * @param to The address that will own the minted token
     * @param tokenId uint256 ID of the token to be minted
     */
    function _mint(address to, uint256 tokenId) internal {
        require(to != address(0), "ERC721: tạo đến địa chỉ không hợp lệ");
        require(!_exists(tokenId), "ERC721: token đã được tạo");

        _tokenOwner[tokenId] = to;
        _ownedTokensCount[to].increment();

        emit Transfer(address(0), to, tokenId);
    }

    /**
     * @dev Hàm nội bộ để đốt token cụ thể.
     * Hoàn ngược nếu token không tồn tại.
     * Đã lỗi thời, sử dụng _burn(uint256) để thay thế.
     * @param owner owner of the token to burn
     * @param tokenId uint256 ID of the token being burned
     */
    function _burn(address owner, uint256 tokenId) internal {
        require(ownerOf(tokenId) == owner, "ERC721: đốt token không thuộc sở hữu");

        _clearApproval(tokenId);

        _ownedTokensCount[owner].decrement();
        _tokenOwner[tokenId] = address(0);

        emit Transfer(owner, address(0), tokenId);
    }

    /**
     * @dev Hàm nội bộ để đốt token cụ thể.
     * Hoàn ngược nếu token không tồn tại.
     * @param tokenId uint256 ID of the token being burned
     */
    function _burn(uint256 tokenId) internal {
        _burn(ownerOf(tokenId), tokenId);
    }

    /**
     * @dev Hàm nội bộ để chuyển quyền sở hữu ID token cụ thể cho một địa chỉ khác.
     * Không giống như transferFrom, hàm này không áp đặt bất kỳ hạn chế nào đối với msg.sender.
     * @param from current owner of the token
     * @param to address to receive the ownership of the given token ID
     * @param tokenId uint256 ID of the token to be transferred
     */
    function _transferFrom(address from, address to, uint256 tokenId) internal {
        require(ownerOf(tokenId) == from, "ERC721: chuyển token không thuộc sở hữu");
        require(to != address(0), "ERC721: chuyển đến địa chỉ không hợp lệ");

        _clearApproval(tokenId);

        _ownedTokensCount[from].decrement();
        _ownedTokensCount[to].increment();

        _tokenOwner[tokenId] = to;

        emit Transfer(from, to, tokenId);
    }

    /**
     * @dev Hàm nội bộ để gọi `onERC721Received` trên địa chỉ đích.
     * Lệnh gọi không được thực hiện nếu địa chỉ đích không phải là hợp đồng.
     *
     * Hàm này đã lỗi thời.
     * @param from address representing the previous owner of the given token ID
     * @param to target address that will receive the tokens
     * @param tokenId uint256 ID of the token to be transferred
     * @param _data bytes optional data to send along with the call
     * @return bool whether the call correctly returned the expected magic value
     */
    function _checkOnERC721Received(address from, address to, uint256 tokenId, bytes memory _data)
        internal returns (bool)
    {
        if (!to.isContract()) {
            return true;
        }

        bytes4 retval = IERC721Receiver(to).onERC721Received(msg.sender, from, tokenId, _data);
        return (retval == _ERC721_RECEIVED);
    }

    /**
     * @dev Hàm riêng tư để xóa trạng thái chấp thuận hiện tại của ID token đã cho.
     * @param tokenId uint256 ID of the token to be transferred
     */
    function _clearApproval(uint256 tokenId) private {
        if (_tokenApprovals[tokenId] != address(0)) {
            _tokenApprovals[tokenId] = address(0);
        }
    }
}

contract MyERC721Card is ERC721{

    struct Card {
        string  name;  // Name of the Card
        uint256 level; // Level of the Card
    }

    Card[] public cards; // First Item has Index 0
    address public owner;

    constructor () public {
        owner = msg.sender; // owner of MyERC721Card contract who can create a new card
    }

    function mintCard(string memory name, address tài khoản) public {
        require(owner == msg.sender); // Chỉ Chủ sở hữu mới có thể tạo các mục
        uint256 cardId = cards.length; // Unique card ID
        cards.push(Card(name, 1));
        _mint(tài khoản, cardId); // Mint a new card
    }

}
```

`MyERC721Card.sol` bao gồm một giao diện(`IERC165`), ba thư viện(`Address`, `SafeMath` và `Counters`) và bốn hợp đồng(`ERC165`, `IERC721`, `IERC721Receiver` và `MyERC721Card`).

* Giao diện `IERC165` xác định giao diện được mô tả trong [tiêu chuẩn kỹ thuật của ERC-165](https://eips.ethereum.org/EIPS/eip-165).
* Thư viện `Address` xác định phương pháp `isContract` để kiểm tra xem `tài khoản` có phải là hợp đồng hay không.
* Thư viện `SafeMath` xác định các lớp bọc (wrapper) cho các phép toán số học trong Solidity, kèm theo kiểm tra tràn số để đảm bảo tính toàn vẹn của phép tính với kiểu `uint256` trong Solidity.
* Thư viện `Counters` xác định các bộ đếm chỉ có thể tăng hoặc giảm đi một đơn vị. Thư viện này được sử dụng để theo dõi số lượng phần tử khi phát hành các id ERC721.
* Hợp đồng `ERC165` triển khai giao diện `IERC165`.
* Hợp đồng `IERC721` xác định giao diện được mô tả trong [tiêu chuẩn kỹ thuật của ERC-721](https://eips.ethereum.org/EIPS/eip-721), bao gồm cả ERC-165.
* Hợp đồng `IERC721Receiver` xác định `onERC721Received` được sử dụng từ hợp đồng `MyERC721Card`.
* Hợp đồng `ERC721` triển khai `IERC721` và `ERC165`.
* Hợp đồng `MyERC721Card` triển khai một token không thể thay thế (NFT) theo kiểu thẻ với tên và cấp độ sử dụng hợp đồng `ERC721` và chỉ chủ sở hữu hợp đồng `MyERC721Card` mới có thể tạo các thẻ mới.

## 1.2 Tìm hiểu một số phương pháp quan trọng <a href="#id-1-2-take-a-look-at-important-methods" id="id-1-2-take-a-look-at-important-methods"></a>

Hãy tìm hiểu chi tiết một số phương pháp quan trọng.

### (1) `constructor` của ERC721 và `_INTERFACE_ID_ERC721` <a href="#id-1-constructor-of-erc721-and-_interface_id_erc721" id="id-1-constructor-of-erc721-and-_interface_id_erc721"></a>

`constructor` đăng ký `_INTERFACE_ID_ERC721` là hàm băm 4 byte bắt nguồn từ các giao diện ERC-721 như sau.

```
    /*
     *     bytes4(keccak256('balanceOf(address)')) == 0x70a08231
     *     bytes4(keccak256('ownerOf(uint256)')) == 0x6352211e
     *     bytes4(keccak256('approve(address,uint256)')) == 0x095ea7b3
     *     bytes4(keccak256('getApproved(uint256)')) == 0x081812fc
     *     bytes4(keccak256('setApprovalForAll(address,bool)')) == 0xa22cb465
     *     bytes4(keccak256('isApprovedForAll(address,address)')) == 0xe985e9c
     *     bytes4(keccak256('transferFrom(address,address,uint256)')) == 0x23b872dd
     *     bytes4(keccak256('safeTransferFrom(address,address,uint256)')) == 0x42842e0e
     *     bytes4(keccak256('safeTransferFrom(address,address,uint256,bytes)')) == 0xb88d4fde
     *
     *     => 0x70a08231 ^ 0x6352211e ^ 0x095ea7b3 ^ 0x081812fc ^
     *        0xa22cb465 ^ 0xe985e9c ^ 0x23b872dd ^ 0x42842e0e ^ 0xb88d4fde == 0x80ac58cd
     */
    bytes4 private constant _INTERFACE_ID_ERC721 = 0x80ac58cd;

    constructor () public {
        // register the supported interfaces to conform to ERC721 via ERC165
        _registerInterface(_INTERFACE_ID_ERC721);
    }
```

Sau khi đăng ký, giao diện `supportsInterface` của hợp đồng ERC-721 và ERC-165 trả về giá trị `true` khi được gọi cho `_INTERFACE_ID_ERC721` và cho biết hợp đồng này đang triển khai các giao diện ERC-721.

### (2) `function balanceOf(address owner) public view returns (uint256 balance);` <a href="#id-2-function-balanceof-address-owner-public-view-returns-uint256-balance" id="id-2-function-balanceof-address-owner-public-view-returns-uint256-balance"></a>

`balanceOf` là một phương pháp bắt buộc của ERC-721. `balanceOf` trả về số lượng token NFT trong tài khoản của `owner`.

```
    function balanceOf(address owner) public view returns (uint256) {
        require(owner != address(0), "ERC721: balance query for the zero address");

        return _ownedTokensCount[owner].current();
    }
```

`balanceOf` chỉ trả về số lượng hiện có từ đối tượng `Counter` mà `owner` duy trì trong `_ownedTokensCount`.

```
    // Ánh xạ từ chủ sở hữu đến số token thuộc sở hữu
    mapping (address => Counters.Counter) private _ownedTokensCount;
```

### (3) `safeTransferFrom` và `transferFrom` <a href="#id-3-safetransferfrom-and-transferfrom" id="id-3-safetransferfrom-and-transferfrom"></a>

Các hàm này chuyển quyền sở hữu của một ID token cụ thể cho một địa chỉ khác. ERC-721 yêu cầu hai phương pháp `safeTransferFrom`, một phương pháp có `data` và một phương pháp không có `data`. Cả hai phương pháp hoạt động tương tự nhau, chỉ khác nhau ở chỗ phương pháp không có `data` chỉ đặt `data` là `""`. `safeTransferFrom` gọi hàm `transferFrom` nếu có nhiều lần kiểm tra hơn như dưới đây và `safeTransferFrom` được ưu tiên sử dụng hơn so với `transferFrom`, đây là phương pháp bắt buộc của ERC-721.

```
    function safeTransferFrom(address from, address to, uint256 tokenId) public {
        safeTransferFrom(from, to, tokenId, "");
    }

    function safeTransferFrom(address from, address to, uint256 tokenId, bytes memory _data) public {
        transferFrom(from, to, tokenId);
        require(_checkOnERC721Received(from, to, tokenId, _data), "ERC721: transfer to non ERC721Receiver implementer");
    }

    function transferFrom(address from, address to, uint256 tokenId) public {
        //solhint-disable-next-line max-line-length
        require(_isApprovedOrOwner(msg.sender, tokenId), "ERC721: transfer caller is not owner nor approved");

        _transferFrom(from, to, tokenId);
    }
```

`safeTransferFrom` kiểm tra xem địa chỉ `to` có thể nhận token hay không. `_checkOnERC721Received` có logic xác minh. Nếu địa chỉ `to` là một hợp đồng thì hợp đồng đó phải thực hiện giao diện `onERC721Received` của ERC-721 và trả về hàm băm 4 byte chính xác để nhận token ERC-721 như sau.

```
    function _checkOnERC721Received(address from, address to, uint256 tokenId, bytes memory _data)
        internal returns (bool)
    {
        if (!to.isContract()) {
            return true;
        }

        bytes4 retval = IERC721Receiver(to).onERC721Received(msg.sender, from, tokenId, _data);
        return (retval == _ERC721_RECEIVED);
    }
```

`_transferFrom` trên thực tế chuyển quyền sở hữu của `tokenId` đã cho như dưới đây.

```
    function _transferFrom(address from, address to, uint256 tokenId) internal {
        require(ownerOf(tokenId) == from, "ERC721: chuyển token không thuộc sở hữu");
        require(to != address(0), "ERC721: chuyển đến địa chỉ không hợp lệ");

        _clearApproval(tokenId);

        _ownedTokensCount[from].decrement();
        _ownedTokensCount[to].increment();

        _tokenOwner[tokenId] = to;

        emit Transfer(from, to, tokenId);
    }
```

### (4) `function _mint(address to, uint256 tokenId) internal` <a href="#id-4-function-_mint-address-to-uint256-tokenid-internal" id="id-4-function-_mint-address-to-uint256-tokenid-internal"></a>

`_mint` không phải là một phần của ERC-721. Tuy nhiên, chúng tôi cần một cách để tạo ra các token ERC-721 mới và đã áp dụng `_mint` để tạo ra các token mới trong lần triển khai này như sau.

```
    function _mint(address to, uint256 tokenId) internal {
        require(to != address(0), "ERC721: tạo đến địa chỉ không hợp lệ");
        require(!_exists(tokenId), "ERC721: token đã được tạo");

        _tokenOwner[tokenId] = to;
        _ownedTokensCount[to].increment();

        emit Transfer(address(0), to, tokenId);
    }
```

`_mint` là một phương pháp nội bộ và có thể được gọi bên trong hợp đồng này. Trong `MyERC721Card.sol`, `_mint` chỉ được gọi từ phương pháp `mintCard` trong hợp đồng `MyERC721Card`. Chỉ có chủ sở hữu hợp đồng thông minh mới có thể gọi `mintCard`.

```
    function mintCard(string name, address tài khoản) public {
        require(owner == msg.sender); // Chỉ Chủ sở hữu mới có thể tạo các mục
        uint256 cardId = cards.length; // ID thẻ duy nhất
        cards.push(Card(name, 1));
        _mint(tài khoản, cardId); // Tạo thẻ mới
    }
```


# 2. Triển khai hợp đồng thông minh

Bạn có thể sử dụng Remix Online IDE hoặc Truffle để triển khai hợp đồng thông minh `MyERC721Card` trên đây.

## 2.1 Triển khai hợp đồng thông minh bằng Remix Online IDE <a href="#id-2-1-deploying-smart-contract-using-klaytn-ide" id="id-2-1-deploying-smart-contract-using-klaytn-ide"></a>

* Vui lòng truy cập [Klaytn Plugin for Remix](https://ide.klaytn.foundation) và tạo hợp đồng `MyERC721Card`. Mã nguồn hoàn chỉnh được cung cấp tại mục [Soạn hợp đồng thông minh ERC-721](/content/smart-contract/sample-contracts/erc-721/1-erc721).
* Tạo một tài khoản để triển khai hợp đồng.
  * Nếu bạn chưa có tài khoản, hãy tạo một tài khoản tại <https://baobab.wallet.klaytn.foundation/create> hoặc \[<https://toolkit.klaytn.foundation/tài> khoản/tài khoảnKeyLegacy]\(<https://toolkit.klaytn.foundation/tài> khoản/tài khoảnKeyLegacy).
  * Nhận một số KLAY thử nghiệm từ faucet - <https://baobab.wallet.klaytn.foundation/faucet>
* Hãy triển khai hợp đồng `MyERC721Card.sol` như dưới đây.

![ERC721-1-deploy](/files/SQHgez2ktWtQcOyWNd9M)

Giờ đây `MyERC721Card` đã hoạt động! Bạn có thể tạo và chuyển đổi các thẻ là các token không thể thay thế tương thích với ERC-721.

Hãy tạo hai thẻ, cụ thể là thẻ `King` và `Queen`, cho tài khoản `0x2645BA5Be42FfEe907ca8e9d88f6Ee6dAd8c1410` như dưới đây.

![ERC721-2-mint-king](/files/jSHYr8WALGcey0yeUM8c) ![ERC721-3-mint-queen](/files/eHeLgem6p8zmlKqcyfuk)

Giờ chúng ta đã tạo được hai thẻ và hãy kiểm tra trạng thái của các token không thể thay thế `MyERC721Card` này.

![ERC721-4-cards-trạng thái](/files/l2QZjgAfSGO1wnCmiiuX)

* `balanceOf` thể hiện rằng tài khoản `0x2645BA5Be42FfEe907ca8e9d88f6Ee6dAd8c1410` có hai thẻ.
* `cards` có tham số `1` thể hiện rằng `MyERC721Card` với ID token `1` là thẻ `Queen` cấp độ 1.
* `ownerOf` có tham số `0` thể hiện rằng chủ sở hữu của `MyERC721Card` với ID token `0` là `0x2645BA5Be42FfEe907ca8e9d88f6Ee6dAd8c1410`.

## 2.2 Triển khai hợp đồng thông minh bằng truffle <a href="#id-2-2-deploying-smart-contract-using-truffle" id="id-2-2-deploying-smart-contract-using-truffle"></a>

Bạn nên cài đặt xong [node.js](https://nodejs.org/) trong môi trường của mình. Hãy xem [Hướng dẫn cài đặt Node.js qua trình quản lý gói](https://nodejs.org/en/download/package-manager/) để cài đặt node.js bằng trình quản lý gói trong các môi trường khác nhau.

```
$ mkdir klaytn
$ cd klaytn
$ npm init # initialize npm at the erc20token directory
$ npm install truffle@4.1.15
$ npm install caver-js@latest # installing caver-js
$ ln -s node_modules/truffle/build/cli.bundled.js truffle
$ export PATH=`pwd`:$PATH
```

Giờ đây, bạn đã cài đặt truffle và caver-js, hai công cụ cần thiết để triển khai hợp đồng thông minh.

Hãy chuẩn bị `truffle` và một hợp đồng thông minh `MyERC721Card.sol`.

```
$ mkdir myerc721
$ cd myerc721
$ truffle init
```

Giờ bạn sẽ có các cấu trúc thư mục như sau.

```
.
├── contracts
│   ├── Migrations.sol
├── migrations
│   └── 1_initial_migration.js
└── truffle-config.js
```

Sau khi soạn hợp đồng `MyERC721Card.sol` và đặt nó vào thư mục `contracts`, cấu trúc thư mục sẽ như dưới đây.

Giờ bạn sẽ có các cấu trúc thư mục như sau.

```
.
├── contracts
│   ├── Migrations.sol
│   └── MyERC721Card.sol
├── migrations
│   └── 1_initial_migration.js
└── truffle-config.js
```

Ngoài ra, chỉnh sửa `1_initial_migration.js` như trình bày dưới đây để triển khai hợp đồng `MyERC721Card`.

```javascript
const Migrations = artifacts.require("./Migrations.sol");
const MyERC721Card = artifacts.require("./MyERC721Card.sol");
module.exports = function(deployer) {
  deployer.deploy(Migrations);
  deployer.deploy(MyERC721Card)
};
```

Bạn cũng phải cấu hình tập tin `truffle-config.js` để triển khai hợp đồng thông minh lên mạng lưới Klaytn. Bước này giống như bước được mô tả tại mục [Triển khai Hợp đồng thông minh bằng Truffle](/content/getting-started/quick-start/deploy-a-smart-contract#deploying-a-smart-contract-using-truffle)

```
// truffle-config.js
module.exports = {
    networks: {
        baobab: {
            host: '127.0.0.1',
            port: 8551,
            from: '0xabcdabcdabcdabcdabcdabcdabcdabcdabcdabcd', // nhập địa chỉ hợp đồng của bạn
            network_id: '1001', // id mạng Baobab
            gas: 20000000, // giới hạn gas của giao dịch
            gasPrice: 250000000000, // gasPrice của Baobab là 250 ston
        },
    },
    compilers: {
      solc: {
        version: "0.5.12"    // Chỉ định phiên bản trình biên dịch là 0.5.12
      }
  }
};
```

Giờ đây bạn đã sẵn sàng, hãy cùng triển khai `MyERC721Card.sol` bằng lệnh như sau.

```
$ truffle deploy --network baobab --reset
Compiling ./contracts/MyERC721Card.sol...
Soạn các tập tin artifact trong thư mục ./build/contracts

Sử dụng mạng lưới 'baobab'.

Running migration: 1_initial_migration.js
  Replacing Migrations...
  ... 0x5a947f076f4570dff8ff18b1ae3557e27dd69c92ce38a3c97fad8f5355914066
  Migrations: 0x0d737e9865e5fc4c1ff53744fd2c13c52a44b9bc
  Deploying MyERC721Card...
  ... 0x1571e80552dab1d67260e8914e06d9b16ccae16fb698c750f6a09aab12517bc1
  MyERC721Card: 0xc3d282926871c505f334d0f2c85ad52758347831
Lưu quá trình di chuyển thành công lên mạng...
  ... 0x5b984b3f79c425d80470a96d5badb857fc05e7f31d94423044ae3119c639aa77
Lưu các tập tin artifact...
```

Đầu ra bảng điều khiển thể hiện hàm băm giao dịch để triển khai hợp đồng `MyERC721Card` là `0x1571e80552dab1d67260e8914e06d9b16ccae16fb698c750f6a09aab12517bc1` và địa chỉ của `MyERC721Card` là `0xc3d282926871c505f334d0f2c85ad52758347831`.


# Hướng dẫn kiểm thử

Trong phần này, chúng tôi sẽ giới thiệu cách kiểm thử các hợp đồng thông minh. Các giao dịch trên blockchain không thể hoàn tác. Do đó, việc kiểm thử hợp đồng thông minh của bạn trước khi triển khai có vai trò rất quan trọng.

## Kiểm thử bằng Truffle <a href="#testing-with-truffle" id="testing-with-truffle"></a>

Truffle cung cấp công cụ kiểm thử tự động. Công cụ này cho phép bạn viết các kiểm thử đơn giản và dễ quản lý theo hai cách khác nhau:

* Bằng `Javascript` và `TypeScript`, để thực hiện kiểm thử các hợp đồng từ bên ngoài, giống như ứng dụng.
* Bằng `Solidity`, để thực hiện kiểm thử trước các hợp đồng, trong các tình huống không có hệ điều hành hoặc ứng dụng.

### 1) Bắt đầu <a href="#id-1-getting-started" id="id-1-getting-started"></a>

Chúng ta sẽ làm theo [Hướng dẫn triển khai bằng Truffle](/content/smart-contract/deploy-guide#truffle) để tạo và triển khai một hợp đồng. Tuy nhiên, trước khi triển khai, chúng ta sẽ thêm một hàm thiết lập `setGreet` vào hợp đồng nhằm mục đích kiểm thử. Mã nguồn được đưa ra như sau.

**LƯU Ý:** Chúng tôi đã thực hiện một số sửa đổi với hợp đồng nhằm mục đích kiểm thử.

Dưới đây là mã nguồn của hợp đồng KlaytnGreeting.

```
pragma solidity 0.5.6;

hợp đồng Mortal {
    /* Xác định biến chủ sở hữu của loại hợp đồng */
    address payable owner;
    /* Hàm này được thực thi khi khởi tạo và thiết lập chủ sở hữu hợp đồng */
    constructor () public { owner = msg.sender; }
    /* Hàm khôi phục số dư trên hợp đồng */
    function kill() public payable { if (msg.sender == owner) selfdestruct(owner); }
}

hợp đồng KlaytnGreeter là Mortal {
    /* Xác định biến lời chào của loại chuỗi */
    string greeting;
    /* Hàm này chạy khi hợp đồng được thực thi */
    constructor (string memory _greeting) public {
        greeting = _greeting;
    }
    /* Hàm chính */
    function greet() public view returns (string memory) {
        return greeting;
    }

    /* Hàm mới thêm để kiểm thử. */
    function setGreet(string memory _greeting) public {
        // only owner can change greeting message
        require(msg.sender == owner, "Only owner is allowed.");
        greeting = _greeting;
    }
}
```

Chúng ta sẽ kiểm thử 1) hàm `greet()` để xem nó có trả về thông báo "Hello, Klaytn" một cách chính xác không, 2) hàm `setGreet()` để xem nó có thiết lập thông báo chào mừng mới một cách chính xác không và hoàn ngược khi tài khoản không phải là chủ sở hữu cố gắng cập nhật thông báo chào mừng không.

Đầu tiên, chúng ta sẽ cài đặt thư viện công cụ khẳng định Chai (hoặc bất kỳ thư viện công cụ khẳng định khác bạn sử dụng) cho các khẳng định chung và thư viện công cụ khẳng định truffle cho các khẳng định trong hợp đồng thông minh.

```
npm install --save-dev chai truffle-assertions
```

### 2) Viết kiểm thử bằng Solidity <a href="#id-2-writing-test-in-solidity" id="id-2-writing-test-in-solidity"></a>

Kiểm thử bằng Solidity có thể trực quan hơn một chút so với kiểm thử bằng JavaScript. Các hợp đồng kiểm thử Solidity được lưu trữ cùng với các kiểm thử JavaScript dưới dạng tập tin .sol.

Tạo một tập tin có tên là `TestKlaytnGreeting.sol` trong thư mục `test`. Bộ công cụ Truffle cung cấp các thư viện hỗ trợ kiểm thử, vì vậy chúng ta cần nhập các thư viện này. Hãy cùng xem ví dụ kiểm thử bằng Solidity dưới đây:

```
pragma solidity ^0.5.6;

import "truffle/Assert.sol";
import "truffle/DeployedAddresses.sol";
import "../contracts/HashMarket.sol";
```

* Assert : Cho phép chúng ta truy cập vào các hàm kiểm thử khác nhau, như `Assert.equals()`, `Assert.greaterThan()`, v.v.
* DeployedAddresses : Mỗi khi bạn thay đổi hợp đồng của mình, bạn phải triển khai lại hợp đồng để có một địa chỉ mới. Bạn có thể lấy các địa chỉ hợp đồng đã triển khai thông qua thư viện này.

Bây giờ, hãy cùng viết mã kiểm thử.

```
pragma solidity ^0.5.6;

import "truffle/Assert.sol";
import "truffle/DeployedAddresses.sol";
import "../contracts/KlaytnGreeter.sol";

contract TestKlaytnGreeter {

    function testGreetingMessage() public {
        // DeployedAddresses.KlaytnGreeter() handles contract address.
        KlaytnGreeter greeter = KlaytnGreeter(DeployedAddresses.KlaytnGreeter());

        string memory expectedGreet = "Hello Klaytn";

        string memory greet = greeter.greet();

        Assert.equal(greet, expectedGreet, "greeting message should match");
    }
}
```

Chạy mã kiểm thử Solidity của bạn.

```
$ truffle test
# Output
Using network 'development'.


Compiling your contracts...
===========================
> Compiling ./test/TestKlaytnGreeter.sol



  TestKlaytnGreeter
    1) testGreetingMessage

    Events emitted during test:
    ---------------------------


    ---------------------------


  0 thành công (5s)
  1 lỗi

  1) TestKlaytnGreeter
       testGreetingMessage:
     Error: greeting message should match (Tested: Hello, Klaytn, Against: Hello Klaytn)
      at result.nhật ký.forEach.log (/Users/jieunkim/.nvm/versions/node/v10.16.0/lib/node_modules/truffle/build/webpack:/packages/core/lib/testing/soliditytest.js:71:1)
      at Array.forEach (<anonymous>)
      at processResult (/Users/jieunkim/.nvm/versions/node/v10.16.0/lib/node_modules/truffle/build/webpack:/packages/core/lib/testing/soliditytest.js:69:1)
      at process._tickCallback (internal/process/next_tick.js:68:7)
```

Đã xảy ra lỗi. Hãy kiểm tra thông báo lỗi,`Error: greeting message should match (Tested: Hello, Klaytn, Against: Hello Klaytn)`. Tôi để ý thấy thiếu dấu `',(comma)'` ở *bộ nhớ chuỗi expectedGreet = "Hello Klaytn"*.\
Sửa mã và chạy thử lần nữa.

```
$ truffle test
# Output
Using network 'development'.


Compiling your contracts...
===========================
> Compiling ./test/TestKlaytnGreeter.sol



  TestKlaytnGreeter
    ✓ testGreetingMessage (58ms)


  1 thành công (5s)
```

Xin chúc mừng! Bạn đã kiểm thử thành công.

### 3) Viết kiểm thử bằng JavaScript <a href="#id-3-writing-test-in-javascript" id="id-3-writing-test-in-javascript"></a>

Truffle sử dụng công cụ kiểm thử [Mocha](https://mochajs.org/) và thư viện công cụ khẳng định [Chai](https://www.chaijs.com/) để cung cấp công cụ vững chắc cho kiểm thử bằng JavaScript. Kiểm thử bằng JavaScript linh hoạt hơn và cho phép bạn viết các kiểm thử phức tạp hơn.

Hãy tạo một tập tin và đặt tên là `0_KlaytnGreeting.js` dưới thư mục `test`.\
Mã kiểm thử là:

```javascript
// Tương tác trực tiếp với hợp đồng KlaytnGreeter
const KlaytnGreeter = artifacts.require("./KlaytnGreeter.sol");
const truffleAssert = require('truffle-assertions');

contract("KlaytnGreeter", async(tài khoảns) => {
    // lưu trữ phiên bản hợp đồng ở cấp cao hơn 
    // cho phép truy cập từ tất cả các hàm.
    var klaytnGreeterInstance;
    var owner = tài khoảns[0];
    var greetMsg = "Hello, Klaytn";

    // Đoạn mã này sẽ chạy trước khi mỗi kiểm thử được thực hiện.
    before(async function() {
        // thiết lập phiên bản hợp đồng vào biến
        klaytnGreeterInstance = await KlaytnGreeter.new(greetMsg, {from:owner});
    })

    it("#1 check Greeting message", async function() {
        // thiết lập thông báo chào mừng dự kiến
        var expectedGreeting = greetMsg;
        var greet= await klaytnGreeterInstance.greet();
        assert.equal(expectedGreeting, greet, "greeting message should match");

    })

    it("#2 update greeting message.", async function() {
        var newGreeting = "Hi, Klaytn";

        await klaytnGreeterInstance.setGreet(newGreeting, { from:owner });
        var greet = await klaytnGreeterInstance.greet();
        assert.equal(newGreeting, greet, "greeting message should match");
    });

    it("#3 [Failure test] Only owner can change greeting.", async function() {
        var fakeOwner = tài khoảns[1];        
        await truffleAssert.fails(klaytnGreeterInstance.setGreet(greetMsg, { from:fakeOwner }));
    });
});
```

Nếu bạn không quen thuộc với kiểm thử đơn vị `Mocha`, vui lòng tham khảo [tài liệu Mocha](https://mochajs.org/#getting-started).

* Sử dụng `contract()` thay vì `describe()`\
  Về mặt cấu trúc, mã kiểm thử của Truffle không nên khác biệt nhiều so với mã kiểm thử thông thường của Mocha. Kiểm thử của bạn nên chứa mã giúp Mocha nhận ra đó là kiểm thử tự động. Khác biệt giữa kiểm thử Mocha và kiểm thử Truffle là việc sử dụng hàm contract().\ **LƯU Ý** sử dụng hàm `contract()` và sử dụng mảng `tài khoảns` để chỉ định các tài khoản Klaytn đang có sẵn.
* Tóm tắt hợp đồng trong các kiểm thử\
  Vì Truffle không có phương pháp nào để phát hiện hợp đồng nào bạn cần tương tác trong suốt quá trình kiểm thử, bạn phải nêu chi tiết hợp đồng một cách rõ ràng. Một trong các giải pháp là sử dụng phương pháp `artifacts.require()`.
* cú pháp `it`\
  Cú pháp này thể hiện mỗi trường hợp kiểm thử cùng với mô tả. Mô tả sẽ được in ra trên bảng điều khiển khi chạy kiểm thử.
* thư viện `truffle-assertion`\
  Thư viện này cho phép bạn dễ dàng kiểm thử các trường hợp hoàn ngược hoặc các lỗi khác bằng cách sử dụng hàm `truffleAssert.reverts()` và `truffleAssert.fails()`.

Kết quả phải như sau:

```
Using network 'development'.


Compiling your contracts...
===========================
> Everything is up to date, there is nothing to compile.



  Contract: KlaytnGreeter
    ✓ #1 check Greeting message
    ✓ #2 update greeting message. (46ms)
    ✓ #3 [Failure test] Only owner can change greeting.


  3 thành công (158ms)
```

Xin chúc mừng! Bạn đã kiểm thử thành công.

### 4) Chỉ định kiểm thử <a href="#id-4-specifying-test" id="id-4-specifying-test"></a>

Bạn có thể lựa chọn tập tin kiểm thử cần thực thi.

```
truffle test ./test/0_KlaytnGreeting.js
```

Để biết thêm thông tin, vui lòng tham khảo [kiểm thử Truffle](https://www.trufflesuite.com/docs/truffle/testing/testing-your-contracts) và [các lệnh Truffle](https://www.trufflesuite.com/docs/truffle/reference/truffle-commands#test).


# Hướng dẫn triển khai

Có nhiều cách khác nhau để triển khai hợp đồng thông minh trên Klaytn. Tài liệu này cung cấp hướng dẫn từng bước để triển khai một hợp đồng mẫu bằng các công cụ khác nhau. Chúng tôi giả định rằng bạn đã có tài khoản Klaytn với đủ KLAY để thanh toán phí giao dịch. Để tạo một tài khoản, vui lòng truy cập [Ví Klaytn](/content/dapp/developer-tools/getting-started/klaytn-wallet).

## Remix Online IDE <a href="#remix-ide" id="remix-ide"></a>

Mở trình duyệt internet của bạn và truy cập [Klaytn Plugin for Remix](https://ide.klaytn.foundation).

* Thêm tập tin mới.

![](/files/BMu6YHZMWhut3ZhMVvWE)

* Sao chép và dán mã mẫu sau đây (hoặc bất kỳ mã nào bạn muốn triển khai) vào tập tin mới. Mã bao gồm hai hợp đồng được gọi là Mortal và KlaytnGreeter và mã này cho phép bạn chạy thông báo "Hello World!" đơn giản.

```
pragma solidity 0.5.12;

contract Mortal {
    /* Define variable owner of the type address */
    address payable owner;
    /* This function is executed at initialization and sets the owner of the contract */
    constructor () public { owner = msg.sender; }
    /* Function to recover the funds on the contract */
    function kill() public payable { if (msg.sender == owner) selfdestruct(owner); }
}

contract KlaytnGreeter is Mortal {
    /* Define variable greeting of the type string */
    string greeting;
    /* This runs when the contract is executed */
    constructor (string memory _greeting) public {
        greeting = _greeting;
    }
    /* Main function */
    function greet() public view returns (string memory) {
        return greeting;
    }
}
```

* Chọn Trình biên dịch trong bảng biểu tượng. Chọn môi trường EVM mong muốn. Đối với các mạng lưới Klaytn, bạn có thể chọn giữa Baobab (mạng thử nghiệm) và Cypress (mạng chính thức). Nhấp vào `Compile` khi mã nguồn mẫu đã sẵn sàng để được biên dịch trước khi triển khai thực tế.

![](/files/Qcdh1ia7yCE3rKpo93Vz)

* Bây giờ, chúng ta có thể triển khai hợp đồng. Nhấp vào logo Klaytn trong bảng biểu tượng. Nhập tài khoản bằng cách nhấp vào nút hình dấu cộng bên cạnh `Account`. Hãy đảm bảo rằng tài khoản có đủ KLAY để thanh toán cho giao dịch triển khai các hợp đồng thông minh cần thiết.

![](/files/sOTi1AblDbiV81atNsVQ)

* Thiết lập Giới hạn gas và Giá trị cần gửi.
  * Nếu bạn triển khai một hợp đồng phức tạp hơn, bạn có thể cần thiết lập Giới hạn gas cao hơn. Bạn có thể để nguyên giá trị hiện tại trong ví dụ này.
  * Đặt `Value` là 0 trừ khi bạn muốn gửi `KLAY` đến hợp đồng vào thời điểm triển khai.
* Nhập "Hello World!" làm đối số cho hàm khởi tạo và nhấp vào nút `Deploy`.

![](/files/c03Qnmj3DAlVyrRpr11F)

* Nếu hợp đồng được triển khai thành công, bạn sẽ nhìn thấy biên lai giao dịch tương ứng và kết quả chi tiết trên bảng điều khiển.
* Bạn có thể tương tác với hợp đồng bằng cách nhấp vào các nút hàm. Các hàm được đại diện bằng các nút có màu sắc khác nhau. Các hàm `constant` hoặc `pure` trong Solidity có các nút màu xanh (ví dụ như `greet`) và không tạo giao dịch mới, do đó chúng không tốn bất kỳ gas nào. Các nút màu đỏ (ví dụ như `kill`) thể hiện các hàm `payable` thay đổi trạng thái trên blockchain, tiêu thụ gas và có thể nhận giá trị. Các nút màu cam đại diện cho các hàm `non-payable` thay đổi trạng thái của hợp đồng nhưng KHÔNG nhận giá trị.

![](/files/VQIzh6LA7dUaSGkWmVJR)

Để biết thêm chi tiết, vui lòng tham khảo [liên kết](https://github.com/klaytn/klaytn-docs-vn/blob/main/docs/toolkit/klaytn-ide.md) này.

## Truffle <a href="#truffle" id="truffle"></a>

Truffle là bộ khung phổ biến nhất cho việc triển khai và thực thi các hợp đồng thông minh.

* Cài đặt bằng lệnh dưới đây.

```
$ sudo npm install -g truffle
```

* Thiết lập thư mục dự án và cài đặt .`truffle-hdwallet-provider-klaytn`

```
$ mkdir hello-klaytn
$ cd hello-klaytn
$ truffle init
$ npm install truffle-hdwallet-provider-klaytn
```

* Tạo `KlaytnGreeter.sol` dưới thư mục `/contracts` và sao chép đoạn mã sau.

```
pragma solidity 0.5.6;

contract Mortal {
    /* Define variable owner of the type address */
    address payable owner;
    /* This function is executed at initialization and sets the owner of the contract */
    constructor () public { owner = msg.sender; }
    /* Function to recover the funds on the contract */
    function kill() public payable { if (msg.sender == owner) selfdestruct(owner); }
}

contract KlaytnGreeter is Mortal {
    /* Define variable greeting of the type string */
    string greeting;
    /* This runs when the contract is executed */
    constructor (string memory _greeting) public {
        greeting = _greeting;
    }
    /* Main function */
    function greet() public view returns (string memory) {
        return greeting;
    }
}
```

* Sửa đổi `/migrations/1_initial_migration.js` như sau.

```
const Migrations = artifacts.require("./Migrations.sol");
const KlaytnGreeter = artifacts.require("./KlaytnGreeter.sol");
module.exports = function(deployer) {
  deployer.deploy(Migrations);
  deployer.deploy(KlaytnGreeter, 'Hello, Klaytn');
};
```

* Thiết lập `truffle-config.js` như bên dưới. Hãy đảm bảo rằng bạn nhập khóa riêng tư của tài khoản có đủ `KLAY` để triển khai hợp đồng.

```
const HDWalletProvider = require("truffle-hdwallet-provider-klaytn");

const privateKey = "0x3de..." // Nhập khóa riêng tư của bạn;

module.exports = {
  networks: {
    development: {
      host: "localhost",
      port: 8545,
      network_id: "*" // Match any network id
    },
    testnet: {
      provider: () => new HDWalletProvider(privateKey, "https://your.baobab.en.url:8651"),
      network_id: '1001', //Klaytn baobab testnet's network id
      gas: '8500000',
      gasPrice: null
    },
    mainnet: {
      provider: () => new HDWalletProvider(privateKey, "https://your.cypress.en.url:8651"),
      network_id: '8217', //Klaytn mainnet's network id
      gas: '8500000',
      gasPrice: null
    }
  },
  compilers: {
    solc: {
      version: "0.5.6"
    }
  }
};
```

*LƯU Ý*: Không khuyến nghị sử dụng ví dụ này cho mục đích sản xuất. Hãy đặc biệt cẩn trọng khi sử dụng các khóa riêng tư.

* Triển khai trên mạng thử nghiệm Klaytn.

```
$ truffle deploy --network testnet
```

* Triển khai trên mạng chính thức Klaytn.

```
$ truffle deploy --network mainnet
```

Để biết thêm chi tiết, vui lòng tham khảo [liên kết](/content/smart-contract/ide-and-tools/truffle) này.

## VVISP <a href="#vvisp" id="vvisp"></a>

vvisp là một công cụ/bộ khung CLI dễ sử dụng để phát triển các hợp đồng thông minh, do HEACHI LABS cung cấp. Bạn có thể dễ dàng thiết lập môi trường, triển khai và thực thi các hợp đồng thông minh Klaytn với một lệnh duy nhất. Tham khảo liên kết sau để biết thêm chi tiết.

* <https://henesis.gitbook.io/vvisp/deploying-smart-contracts>

## solc & caver-js <a href="#solc-caver-js" id="solc-caver-js"></a>

Một cách khác để triển khai hợp đồng là biên dịch hợp đồng thủ công bằng trình biên dịch solc và triển khai chúng bằng thư viện caver-js.

* Tạo `KlaytnGreeter.sol` và viết đoạn mã sau.

```
pragma solidity 0.5.6;

contract Mortal {
    /* Define variable owner of the type address */
    address payable owner;
    /* This function is executed at initialization and sets the owner of the contract */
    constructor () public { owner = msg.sender; }
    /* Function to recover the funds on the contract */
    function kill() public payable { if (msg.sender == owner) selfdestruct(owner); }
}

contract KlaytnGreeter is Mortal {
    /* Define variable greeting of the type string */
    string greeting;
    /* This runs when the contract is executed */
    constructor (string memory _greeting) public {
        greeting = _greeting;
    }
    /* Main function */
    function greet() public view returns (string memory) {
        return greeting;
    }
}
```

* Cài đặt solc 0.5.6.

```
$ sudo npm install -g solc@0.5.6
```

* Biên dịch hợp đồng.

```
$ solcjs KlaytnGreeter.sol --bin
```

* Cài đặt caver-js.

```
$ npm install caver-js.
```

* Tạo `deploy.js` trong cùng thư mục bằng đoạn mã sau.

```
const Caver = require("caver-js");
const caver = new Caver("https://public-en-baobab.klaytn.net")

const walletInstance = caver.klay.tài khoảns.privateKeyToAccount(
  '0x3de0c9...' // enter your private key to deploy contract with
);
caver.klay.tài khoảns.wallet.add(walletInstance);

const fs = require('fs')
const bytecode = fs.readFileSync('./KlaytnGreeter_sol_KlaytnGreeter.bin') // compiled output

const constructorType = ['string']  // enter appropriate constructor type
const constructorValue = ['Hello, Klaytn!']

const params = caver.klay.abi.encodeParameters(constructorType, constructorValue);

caver.klay.sendTransaction({
  from: caver.klay.tài khoảns.wallet[0].address,
  gas: "50000000",
  data: bytecode.toString() + params.substring(2, params.length)
})
.once("receipt", receipt => {
  console.log(receipt)
})
.once("error", error => {
  console.log(error);
})
```

*LƯU Ý*: Không khuyến nghị sử dụng ví dụ này cho mục đích sản xuất. Hãy đặc biệt cẩn trọng khi sử dụng các khóa riêng tư.

* Triển khai hợp đồng sử dụng môi trường nút mạng.

```
$ node deploy.js
```


# Token tương thích Klaytn

Token tương với thích Klaytn (KCT) là một loại hợp đồng thông minh đặc biệt tuân thủ một số tiêu chuẩn kỹ thuật nhất định. Tất cả những người muốn phát hành token trên Klaytn đều phải tuân thủ tiêu chuẩn kỹ thuật này.

Các tiêu chuẩn token được xác định trong Klaytn như [KIP-7](https://kips.klaytn.foundation/KIPs/kip-7) và [KIP-17](https://kips.klaytn.foundation/KIPs/kip-17).

Có thể xác định các KCT khác để đáp ứng các tiêu chuẩn kỹ thuật cụ thể. Nếu bạn cần các tiêu chuẩn token khác, vui lòng truy cập [Đề xuất cải tiến Klaytn](https://github.com/klaytn/KIPs) và đề xuất một tiêu chuẩn token mới.

## Tiêu chuẩn Fungible Token (KIP-7) <a href="#fungible-token-standard-kip-7" id="fungible-token-standard-kip-7"></a>

Fungible token là các token có tính chất đồng nhất và chia được thành nhiều đơn vị. Mỗi fungible token có thể hoán đổi cho nhau do mỗi đơn vị token đều có cùng giá trị. Tương tự như mỗi tờ tiền một USD đều có giá trị như nhau là một USD. Vì khả năng thay thế là một tính năng cần thiết đối với tiền điện tử trong hầu hết các trường hợp, phần lớn các token trên blockchain đều là fungible token.

Để triển khai các thuộc tính này với hợp đồng thông minh, ta có thể sử dụng tiêu chuẩn token KIP-7. Các token tương thích với KIP-7 triển khai giao diện như sau. Lưu ý rằng [KIP-13](https://kips.klaytn.foundation/KIPs/kip-13) cũng phải được triển khai cùng. Đối với ứng dụng ví, có thể triển khai [giao diện ví](https://kips.klaytn.foundation/KIPs/kip-7#wallet-interface).

```solidity
// IKIP7
event Transfer(address indexed from, address indexed to, uint256 value);
event Approval(address indexed owner, address indexed spender, uint256 value);

function totalSupply() external view returns (uint256);
function balanceOf(address tài khoản) external view returns (uint256);
function transfer(address recipient, uint256 amount) external returns (bool);
function allowance(address owner, address spender) external view returns (uint256);
function approve(address spender, uint256 amount) external returns (bool);
function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);
function safeTransfer(address recipient, uint256 amount, bytes data) external;
function safeTransfer(address recipient, uint256 amount) external;
function safeTransferFrom(address sender, address recipient, uint256 amount, bytes data) external;
function safeTransferFrom(address sender, address recipient, uint256 amount) external;

// IKIP7Metadata (optional)
function name() external view returns (string memory);
function symbol() external view returns (string memory);
function decimals() external view returns (uint8);

// IKIP7Mintable (optional)
function mint(address _to, uint256 _amount) external returns (bool);
function isMinter(address _tài khoản) external view returns (bool);
function addMinter(address _tài khoản) external;
function renounceMinter() external;

// IKIP7Burnable (optional)
function burn(uint256 _amount) external;
function burnFrom(address _tài khoản, uint256 _amount) external;

// IKIP7Pausable (optional)
event Paused(address _tài khoản);
event Unpaused(address _tài khoản);

function paused() external view returns (bool);
function pause() external;
function unpause() external;
function isPauser(address _tài khoản) external view returns (bool);
function addPauser(address _tài khoản) external;
function renouncePauser() external;
```

Dựa trên giao diện trên đây, các nhà phát triển có thể tùy chỉnh token bằng cách thêm các tính năng và logic mới và triển khai chúng trên mạng lưới Klaytn.

Để biết thêm thông tin, hãy tham khảo [tài liệu KIP-7](https://kips.klaytn.foundation/KIPs/kip-7) chính thức.

* Tham khảo ví dụ triển khai tại <https://github.com/klaytn/klaytn-contracts/blob/main/contracts/KIP/token/KIP7/KIP7.sol>.

## Tiêu chuẩn Non-fungible Token (KIP-17) <a href="#non-fungible-token-standard-kip-17" id="non-fungible-token-standard-kip-17"></a>

Non-fungible token (NFT) là một loại token đặc biệt đại diện cho một tài sản duy nhất. Như ý nghĩa của cái tên non-fungible (không thể thay thế), mỗi token đều là duy nhất và không thể phân chia thành các đơn vị. Tính duy nhất này của non-fungible token mở ra những chân trời mới cho quá trình số hóa tài sản. Ví dụ: NFT có thể dùng để đại diện cho tác phẩm nghệ thuật số, vật phẩm trò chơi hoặc bất cứ loại tài sản duy nhất nào và cho phép mọi người giao dịch.t nào và cho phép mọi người giao dịch.

Ví dụ, một game sưu tập trên blockchain như [Cryptokitties](https://www.cryptokitties.co/) triển khai non-fungible token để đại diện cho các con mèo với thông tin di truyền khác nhau. Mỗi con mèo đều là duy nhất và không thể hoán đổi, dẫn đến các token của các con mèo khác nhau có giá trị khác nhau.

Để triển khai non-fungible token, có thể sử dụng [KIP-17](https://kips.klaytn.foundation/KIPs/kip-17). Các hợp đồng token KIP-17 triển khai giao diện như sau. Lưu ý rằng [KIP-13](https://kips.klaytn.foundation/KIPs/kip-13) cũng phải được triển khai cùng. Đối với ứng dụng ví, có thể triển khai [giao diện ví](https://kips.klaytn.foundation/KIPs/kip-17#wallet-interface).

```solidity
// IKIP17
event Transfer(address indexed _from, address indexed _to, uint256 indexed _tokenId);
event Approval(address indexed _owner, address indexed _approved, uint256 indexed _tokenId);
event ApprovalForAll(address indexed _owner, address indexed _operator, bool _approved);

function balanceOf(address _owner) external view returns (uint256);
function ownerOf(uint256 _tokenId) external view returns (address);
function safeTransferFrom(address _from, address _to, uint256 _tokenId, bytes _data) external payable;
function safeTransferFrom(address _from, address _to, uint256 _tokenId) external payable;
function transferFrom(address _from, address _to, uint256 _tokenId) external payable;
function approve(address _approved, uint256 _tokenId) external payable;
function setApprovalForAll(address _operator, bool _approved) external;
function getApproved(uint256 _tokenId) external view returns (address);
function isApprovedForAll(address _owner, address _operator) external view returns (bool);

// IKIP17Metadata (optional)
function name() external view returns (string _name);
function symbol() external view returns (string _symbol);
function tokenURI(uint256 _tokenId) external view returns (string);

// IKIP17Enumerable (optional)
function totalSupply() external view returns (uint256);
function tokenByIndex(uint256 _index) external view returns (uint256);
function tokenOfOwnerByIndex(address _owner, uint256 _index) external view returns (uint256);

// IKIP17Mintable (optional)
function mint(address _to, uint256 _tokenId) public returns (bool);
function isMinter(address _tài khoản) public view returns (bool);
function addMinter(address _tài khoản) public;
function renounceMinter() public;

// IKIP17MetadataMintable (optional)
function mintWithTokenURI(address _to, uint256 _tokenId, string memory _tokenURI) public returns (bool);
function isMinter(address _tài khoản) public view returns (bool);
function addMinter(address _tài khoản) public;
function renounceMinter() public;

// IKIP17Burnable (optional)
function burn(uint256 _tokenId) public;

// IKIP17Pausable (optional)
event Paused(address _tài khoản);
event Unpaused(address _tài khoản);
function paused() public view returns (bool);
function pause() public;
function unpause() public;
function isPauser(address _tài khoản) public view returns (bool);
function addPauser(address _tài khoản) public;
function renouncePauser() public;
```

Dựa trên giao diện trên đây, các nhà phát triển có thể tùy chỉnh token bằng cách thêm các tính năng và logic mới và triển khai chúng trên mạng lưới Klaytn.

Để biết thêm thông tin, hãy tham khảo [tài liệu KIP-17](https://kips.klaytn.foundation/KIPs/kip-17) chính thức.

* Tham khảo ví dụ triển khai tại <https://github.com/klaytn/klaytn-contracts/blob/main/contracts/KIP/token/KIP17/KIP17.sol>.

## Tiêu chuẩn token cho chuỗi dịch vụ Klaytn <a href="#token-standards-for-klaytn-service-chain" id="token-standards-for-klaytn-service-chain"></a>

Chuỗi dịch vụ đề cập đến chuỗi con của Klaytn mà neo vào mạng chính blockchain của Klaytn. Khi triển khai một chuỗi dịch vụ, cần sử dụng các loại hợp đồng đặc biệt để hỗ trợ việc chuyển giá trị giữa chuỗi chính và chuỗi dịch vụ. Hiện tại, các hợp đồng này đang được phát triển và khi sẵn sàng, các tiêu chuẩn kỹ thuật về token cho chuỗi dịch vụ Klaytn sẽ được cung cấp trên KlaytnDocs.

## Lưu ý về ERC-20 và ERC-721 <a href="#notes-on-erc-20-and-erc-721" id="notes-on-erc-20-and-erc-721"></a>

Do Klaytn công bố KIP-7 và KIP-17 là các tiêu chuẩn token được Klaytn sử dụng, chúng tôi khuyến nghị triển khai các hợp đồng fungible và non-fungible token lần lượt theo KIP-7 và KIP-17, thay vì theo ERC-20 và ERC-721. KIP-7 và KIP-17 dựa trên tiêu chuẩn ERC-20 và ERC-721, nhưng được điều chỉnh cho phù hợp với Klaytn và do đó phù hợp hơn trên hệ sinh thái Klaytn. Tuy ERC-20 và ERC-721 vẫn được hỗ trợ trên mạng lưới Klaytn, nhưng chúng có thể không tương thích với các công cụ khác nhau trong hệ sinh thái Klaytn. Để biết thêm thông tin về sự khác biệt giữa các tiêu chuẩn token, vui lòng truy cập [KIP-7](https://kips.klaytn.foundation/KIPs/kip-7#differences-with-erc-20) và [KIP-17](https://kips.klaytn.foundation/KIPs/kip-17#differences-from-erc-721).


# Di chuyển hợp đồng Ethereum

Trong hầu hết các trường hợp, bạn có thể dùng hợp đồng Ethereum trên Klaytn mà không cần sửa đổi. Tuy nhiên, bạn cần lưu ý hai vấn đề sau.

## Hỗ trợ Solidity <a href="#solidity-support" id="solidity-support"></a>

* Mạng lưới Baobab hiện tương thích với Máy ảo Ethereum (EVM) phiên bản **London**.
* Mạng lưới Cypress hiện tương thích với Máy ảo Ethereum (EVM) phiên bản **London**.

{% hint style="success" %}
Nâng cấp giao thức v1.7.0 - thay đổi không tương thích bao gồm các mục liên quan đến hard fork **Istanbul** và các mục riêng của Klaytn. Nó đã được kích hoạt từ số khối `#75,373,312` đối với mạng lưới Baobab và `#86,816,005` đối với mạng lưới Cypress.

Nâng cấp giao thức v1.7.3 - thay đổi không tương thích bao gồm Base Fee từ lần hard fork **London**. Nó đã được kích hoạt từ số khối `#80,295,291` đối với mạng lưới Baobab và `#86,816,005` đối với mạng lưới Cypress.

Nâng cấp giao thức v1.8.0 - thay đổi không tương thích bao gồm Base Fee từ lần hard fork **London**. Nó đã được kích hoạt từ số khối `#86,513,895` đối với mạng lưới Baobab và `#86,816,005` đối với mạng lưới Cypress.
{% endhint %}

Không đảm bảo tính tương thích ngược với các phiên bản EVM khác trên Klaytn. Do đó, chúng tôi đặc biệt khuyến nghị biên dịch mã Solidity với tùy chọn mục tiêu chính xác theo trạng thái nâng cấp giao thức.

* Baobab: --evm-version london
* Cypress: --evm-version london
* Khác (chuỗi riêng/dịch vụ): được xác định theo trạng thái nâng cấp giao thức

Vui lòng tham khảo [cách thiết lập phiên bản EVM của solc](https://solidity.readthedocs.io/en/latest/using-the-compiler.html#setting-the-evm-version-to-target).

Dưới đây là một lệnh ví dụ:

```
$ solc --evm-version london contract.sol
```

## Cặp khóa tách rời <a href="#decoupled-key-pairs" id="decoupled-key-pairs"></a>

Klaytn \[tách riêng cặp khóa khỏi địa chỉ]\(../klaytn/design/tài khoảns.md#decoupling-key-pairs-from-addresses). Nếu người dùng \[cập nhật tài khoản]\(../klaytn/design/transactions/basic.md#txtypetài khoảnupdate), khóa riêng tư cho tài khoản cụ thể sẽ được thay thế bằng một khóa khác. Trong hầu hết các trường hợp, điều này sẽ không ảnh hưởng đến logic kinh doanh của bạn. Tuy nhiên, nếu logic kinh doanh của bạn bao gồm ecrecover, bạn nên cân nhắc sử dụng validateSender. Để biết thêm chi tiết, hãy tham khảo [tại đây](/content/smart-contract/precompiled-contracts).


# Chạy một Node


# Triển khai

Dùng thử và làm quen với Klaytn. Chương này là điểm khởi đầu cho hành trình của bạn đến các dApp Klaytn.


# Nút điểm cuối

## Đối tượng mục tiêu <a href="#intended-audience" id="intended-audience"></a>

* Bất kỳ ai muốn gửi giao dịch hoặc truy vấn trạng thái của mạng lưới Klaytn bằng cách sử dụng [API Klaytn](/content/dapp/json-rpc) đều phải thực hiện điều đó thông qua Nút điểm cuối.
* Nút điểm cuối là giao diện của Mạng lưới Klaytn.

## Tổng quan về Nút điểm cuối <a href="#endpoint-node-overview" id="endpoint-node-overview"></a>

Nút điểm cuối có các vai trò và chức năng như sau.

* Đồng bộ hóa dữ liệu blockchain.
* Xác thực các khối mới nhận được.
* Xử lý các yêu cầu truy vấn.
* Truyền các yêu cầu giao dịch đến các Nút Proxy.

Nhị phân cài đặt Nút điểm cuối đi kèm với các giao diện và tiện ích như sau.

* API JSON-RPC: Máy chủ JSON-RPC chạy bên trong nút và cung cấp [API](/content/dapp/json-rpc) để phát triển Ứng dụng Blockchain. Nó cũng có API quản lý nút.
* Giao diện dòng lệnh: Cung cấp chức năng quản lý tài khoản và cấu hình nút. Bảng điều khiển JavaScript tương tác cũng được cung cấp và đính kèm nút. Bảng điều khiển JavaScript triển khai hầu hết các [API caver-js](/content/dapp/sdk/caver-js).


# Yêu cầu hệ thống

Chạy Nút điểm cuối (EN) yêu cầu thông số kỹ thuật phần cứng tương đối cao hơn so với chạy Ethereum hoặc các blockchain khác, bởi vì EN phải xác thực các khối được tạo bởi Nút đồng thuận chính thức được trang bị phần cứng cấp doanh nghiệp.

Đối với EN, các thông số kỹ thuật sau đây được khuyến nghị.

## Thông số H/W <a href="#h-w-specification" id="h-w-specification"></a>

### VM đám mây <a href="#cloud-vm" id="cloud-vm"></a>

#### Thông số kỹ thuật khuyến nghị <a href="#recommended-specification-based-on-aws" id="recommended-specification-based-on-aws"></a>

| vCPU | Bộ nhớ (GiB) | Lưu trữ (GiB) | Băng thông ổ đĩa (Mbps) | Băng thông mạng lưới (Gbps) |
| ---- | ------------ | ------------- | ----------------------- | --------------------------- |
| 8    | 64           | > 3.000       | 3.500                   | Lên đến 10                  |

### Máy Bare-metal <a href="#bare-metal-machine" id="bare-metal-machine"></a>

Chúng tôi không chỉ định thông số kỹ thuật máy vật lý chính xác cho EN nhưng bất kỳ máy vật lý nào có cấu hình phần cứng tương tự như cấu hình trong phần VM đám mây sẽ đủ để vận hành EN.

## Yêu cầu lưu trữ <a href="#storage-requirements" id="storage-requirements"></a>

Giả sử trung bình 100 TPS, kích thước giao dịch trung bình 300 byte và độ trễ khối 1 giây, yêu cầu dung lượng EN dự kiến hàng ngày là khoảng 2,5 GB/ngày (=300x100x86400).

## Hệ điều hành <a href="#operating-system" id="operating-system"></a>

Môi trường nên dùng là [Amazon Linux 2](https://aws.amazon.com/ko/about-aws/whats-new/2017/12/introducing-amazon-linux-2/). Nhị phân Klaytn đã được thử nghiệm đầy đủ trên Amazon Linux 2 nhưng chúng cũng có thể hoạt động trên các môi trường chạy trên linux khác. nhị phân macOS cũng được cung cấp cho mục đích phát triển.


# Hướng dẫn cài đặt


# Tải xuống

Bạn có thể tải về các gói cho EN tại [trang tải về](/content/installation-guide/deployment/download).


# Hướng dẫn cài đặt

Bạn có thể tải về phiên bản mới nhất của `ken` trên trang [Tải xuống](/content/installation-guide/deployment/endpoint-node/installation-guide/download).

## Phân bổ lưu trữ Linux <a href="#linux-archive-distribution" id="linux-archive-distribution"></a>

Tập tin lưu trữ bao gồm tập tin nhị phân thực thi và cấu hình có cấu trúc như sau.

**Lưu ý**: KHÔNG thay đổi cấu trúc hoặc tên tập tin. Nếu bạn thay đổi điều đó, nút có thể sẽ không hoạt động đúng.

```
- bin
  |- ken
  |- kend
- conf
  |- kend.conf
```

| Tên tập tin    | Mô tả tập tin                    |
| -------------- | -------------------------------- |
| bin/ken        | Tập tin thực thi EN              |
| bin/kend       | Tập tin lệnh bắt đầu/kết thúc EN |
| conf/kend.conf | Tập tin cấu hình EN              |

### Cài đặt <a href="#installation" id="installation"></a>

Quá trình cài đặt chính là giải nén gói đã tải về tại nơi bạn muốn cài đặt gói.

```
$ tar zxf ken-vX.X.X-linux-amd64.tar.gz
```

Hoặc,

```
$ tar zxf ken-baobab-vX.X.X-linux-amd64.tar.gz
```

**Lưu ý**: nên thêm đường dẫn thư mục chưa giải nén `ken-linux-amd64/bin` vào biến môi trường `$PATH` để chạy `ken` và `kend` trên toàn hệ thống. Ví dụ,

```
$ export PATH=$PATH:~/downloaded/path/ken-linux-amd64/bin
```

Các phần khác giả định rằng đường dẫn đã được thêm vào biến.

## Phân bổ RPM (RHEL/CentOS/Fedora) <a href="#rpm-rhel-centos-fedora" id="rpm-rhel-centos-fedora"></a>

### Cài đặt RPM đã tải về <a href="#install-downloaded-rpm" id="install-downloaded-rpm"></a>

Bạn có thể cài đặt RPM đã tải về với lệnh `yum` sau đây.

```
$ yum install kend-vX.X.X.el7.x86_64.rpm
```

Hoặc,

```
$ yum install kend-baobab-vX.X.X.el7.x86_64.rpm
```

### Cài đặt từ Klaytn Yum Repo <a href="#install-from-klaytn-yum-repo" id="install-from-klaytn-yum-repo"></a>

Ngoài ra, bạn có thể cài đặt `kend` từ Klaytn Yum repo, chạy:

```
$ sudo curl -o /etc/yum.repos.d/klaytn.repo https://packages.klaytn.net/config/rhel/7/prod.repo && sudo yum install kend
```

### Vị trí đã cài đặt <a href="#installed-location" id="installed-location"></a>

Tập tin đã cài đặt nằm ở vị trí như sau.

| Tên tập tin | Vị trí                   |
| ----------- | ------------------------ |
| ken         | /usr/bin/ken             |
| kend.conf   | /etc/kend/conf/kend.conf |


# Cấu hình

Cấu hình EN dùng để tạo thư mục dữ liệu và thiết lập các biến môi trường trong tập tin cấu hình `kend.conf`.

1. Tạo thư mục dữ liệu EN.
2. Định cấu hình EN với `kend.conf`.

## Tạo thư mục dữ liệu EN <a href="#en-data-directory-creation" id="en-data-directory-creation"></a>

Kích thước của dữ liệu blockchain Klaytn sẽ luôn tăng lên nên cần sử dụng một dung lượng lưu trữ đủ lớn. Bạn cần phải tạo thư mục trên đường dẫn bạn muốn.

```
$ sudo mkdir -p /var/kend/data
```

## Cập nhật Tập tin cấu hình <a href="#update-the-configuration-file" id="update-the-configuration-file"></a>

Vị trí tập tin cấu hình:

* Nếu phân bổ lưu trữ, vị trí thư mục cấu hình mặc định là `$INSTALL_PATH/ken-linux-amd64/conf/`.
* Nếu phân bổ gói, vị trí thư mục cấu hình mặc định là `/etc/kpnd/conf/`.

### Thêm Thư mục dữ liệu <a href="#add-data-directory" id="add-data-directory"></a>

Bạn nên cập nhật biến môi trường thư mục dữ liệu `$DATA_DIR`trên tập tin cấu hình `kend.conf`.

```
DATA_DIR=/var/kend/data
```

## Đồng bộ nhanh (Tùy chọn) <a href="#fast-sync-optional" id="fast-sync-optional"></a>

Mỗi EN duy trì một bản sao dữ liệu chuỗi của mạng lưới. Nếu một nút không được đồng bộ, nút này có thể lấy dữ liệu này từ các nút khác trong mạng lưới -- một quá trình được gọi là đồng bộ hóa. Khi một EN mới được bắt đầu lần đầu tiên, nó phải tải xuống toàn bộ dữ liệu chuỗi từ mạng lưới.

Để đẩy nhanh quá trình này, bạn cần thực hiện đồng bộ nhanh bằng cách tải về bản thu thập dữ liệu của dữ liệu chuỗi trước khi bắt đầu EN. Điều này giúp giảm đáng kể thời gian EN cần để đồng bộ khi bắt đầu lần đầu tiên.

Tải xuống bản thu thập dữ liệu chuỗi mới nhất từ [Lưu trữ thu thập dữ liệu Cypress](http://packages.klaytn.net/cypress/chaindata/) hoặc[Lưu trữ thu thập dữ liệu Baobab](http://packages.klaytn.net/baobab/chaindata/). Trước khi bắt đầu `kend`, trích xuất bản thu thập dữ liệu trong DATA\_DIR mà bạn định cấu hình trong `kend.conf`.

Ví dụ:

```bash
$ tar -C ~/kend_home -xvf klaytn-cypress-chaindata-latest.tar.gz
```

Hoặc,

```bash
$ tar -C ~/kend_home -xvf klaytn-baobab-chaindata-latest.tar.gz
```

Sau khi dữ liệu được trích xuất, bạn có thể bắt đầu EN như bình thường.

Bạn có thể tham khảo thông tin chi tiết tại [Thay đổi dữ liệu chuỗi](/content/operation-guide/chaindata-change)

## &#x20;<a href="#en-start-stop-status" id="en-start-stop-status"></a>


# Khởi động EN

Bạn có thể bắt đầu hoặc dừng Nút điểm cuối bằng các lệnh sau.

**bắt đầu**

```bash
$ kend start
Starting kend: OK
```

**dừng**

```bash
$ kend stop
Shutting down kend: Killed
```

**trạng thái**

```bash
$ kend trạng thái
kend is running
```


# Thử việc cài đặt

Đã đến lúc kiểm tra xem Nút điểm cuối đã được cài đặt thành công chưa và nó có hoạt động như mong đợi sau khi cài đặt không.

## Tình trạng xử lý <a href="#process-status" id="process-status"></a>

Có thể kiểm tra trạng thái quy trình của EN bằng các lệnh trạng thái `systemctl` và `kend`.

### systemctl <a href="#systemctl" id="systemctl"></a>

`systemctl` được cài đặt cùng với RPM; có thể kiểm tra trạng thái của EN như sau.

```bash
$ systemctl trạng thái kend.service
● kend.service - (null)
   Loaded: loaded (/etc/rc.d/init.d/kend; bad; vendor preset: disabled)
   Active: active (running) since Wed 2019-01-09 11:42:39 UTC; 1 months 4 days ago
     Docs: man:systemd-sysv-generator(8)
  Process: 29636 ExecStart=/etc/rc.d/init.d/kend start (code=exited, trạng thái=0/SUCCESS)
 Main PID: 29641 (ken)
   CGroup: /system.slice/kend.service
           └─29641 /usr/local/bin/ken --networkid 1000 --datadir /kend_home --port 32323 --srvtype fasthttp --metrics --prometheus --verbosity 3 --txpool.global...

Jan 09 11:42:39 ip-10-11-2-101.ap-northeast-2.compute.internal systemd[1]: Starting (null)...
Jan 09 11:42:39 ip-10-11-2-101.ap-northeast-2.compute.internal kend[29636]: Starting kend: [  OK  ]
Jan 09 11:42:39 ip-10-11-2-101.ap-northeast-2.compute.internal systemd[1]: Started (null).
```

Bạn có thể kiểm tra trạng thái hiện tại như `Active: active (running)` trong ví dụ bên dưới.

### kend <a href="#kend" id="kend"></a>

`kend` được cài đặt cùng với gói; trạng thái của EN có thể được kiểm tra như sau.

```bash
$ kend trạng thái
kend is running
```

## Nhật ký <a href="#logs" id="logs"></a>

Nhật ký được lưu trữ trong tập tin `kend.out` được đặt tại đường dẫn xác định trong trường `LOG_DIR` của tập tin `kend.conf`. Khi nút hoạt động bình thường, bạn có thể thấy rằng mỗi khối được nhập theo từng giây như sau.

Ví dụ:

```bash
$ tail kend.out
INFO[02/13,07:02:24 Z] [35] Commit new mining work                    number=11572924 txs=0 elapsed=488.336µs
INFO[02/13,07:02:25 Z] [5] Imported new chain segment                blocks=1 txs=0 mgas=0.000     elapsed=1.800ms   mgasps=0.000       number=11572924 hash=f46d09…ffb2dc cache=1.59mB
INFO[02/13,07:02:25 Z] [35] Commit new mining work                    number=11572925 txs=0 elapsed=460.485µs
INFO[02/13,07:02:25 Z] [35] 🔗 block reached canonical chain           number=11572919 hash=01e889…524f02
INFO[02/13,07:02:26 Z] [14] Committed                                 address=0x1d4E05BB72677cB8fa576149c945b57d13F855e4 hash=1fabd3…af66fe number=11572925
INFO[02/13,07:02:26 Z] [5] Imported new chain segment                blocks=1 txs=0 mgas=0.000     elapsed=1.777ms   mgasps=0.000       number=11572925 hash=1fabd3…af66fe cache=1.59mB
INFO[02/13,07:02:26 Z] [35] Commit new mining work                    number=11572926 txs=0 elapsed=458.665µs
INFO[02/13,07:02:27 Z] [14] Committed                                 address=0x1d4E05BB72677cB8fa576149c945b57d13F855e4 hash=60b9aa…94f648 number=11572926
INFO[02/13,07:02:27 Z] [5] Imported new chain segment                blocks=1 txs=0 mgas=0.000     elapsed=1.783ms   mgasps=0.000       number=11572926 hash=60b9aa…94f648 cache=1.59mB
INFO[02/13,07:02:27 Z] [35] Commit new mining work      
```

## Truy vấn <a href="#queries" id="queries"></a>

### ken console <a href="#ken-console" id="ken-console"></a>

Klaytn cung cấp một máy khách CLI: `ken console`. Một cách khác để sử dụng máy khách là kết nối với quy trình thông qua IPC (giao tiếp giữa các quy trình). Tập tin IPC `klay.ipc` được đặt tại thư mục `data` trên một EN.

Hãy thực hiện lệnh sau và kiểm tra kết quả.

```
$ ken attach /var/kend/data/klay.ipc
Chào mừng bạn đến với bảng điều khiển Klaytn JavaScript!

instance: Klaytn/vX.X.X/XXXX-XXXX/goX.X.X
 datadir: /var/kend/data
 modules: admin:1.0 debug:1.0 governance:1.0 istanbul:1.0 klay:1.0 miner:1.0 net:1.0 personal:1.0 rpc:1.0 txpool:1.0
 >
```

Bạn có thể kiểm tra các lệnh có thể sử dụng trên [Tài liệu API](/content/dapp/json-rpc)

Các API hữu ích để kiểm tra trạng thái của EN:

* `klay.blockNumber` (để lấy số khối mới nhất)
* `net.peerCount` (để lấy số nút Klaytn được kết nối hiện tại)

### klay.blockNumber <a href="#klay-blocknumber" id="klay-blocknumber"></a>

Bạn có thể lấy số khối mới nhất để xem các khối có được truyền đúng cách không.

```
> klay.blockNumber
11573819
```

### net.peerCount <a href="#net-peercount" id="net-peercount"></a>

```
> net.peerCount
14
```

Dòng lệnh trên trả về số nút mà EN kết nối đến.


# các lệnh CLI ken

`ken` là giao dịch dòng lệnh cho Nút điểm cuối Klaytn.

```bash
CÁCH SỬ DỤNG:
   lệnh ken [options] [tùy chọn lệnh] [arguments...]
```

## Lệnh <a href="#commands" id="commands"></a>

`ken` có các lệnh sau.

```bash
LỆNH:
   tài khoản     Quản lý tài khoản
   attach      Bắt đầu một môi trường JavaScript tương tác (kết nối với nút)
   console     Bắt đầu một môi trường JavaScript tương tác
   dumpconfig  Hiển thị giá trị cấu hình
   dumpgenesis Kết xuất cấu hình JSON của khối khởi nguyên sang stdout (Lệnh này được hỗ trợ từ Klaytn v1.7.0.)
   init        Bootstrap và khởi tạo một khối khởi nguyên mới
   snapshot    Một tập hợp các lệnh dựa trên thu thập dữ liệu
   version     Hiển thị số phiên bản
   help, h     Hiển thị danh sách các lệnh hoặc trợ giúp cho một lệnh
```

Để xem hướng dẫn sử dụng chi tiết cho từng lệnh, hãy chọn tùy chọn `-h`.

```bash
$ ken tài khoản -h
Quản lý tài khoản, liệt kê tất cả các tài khoản hiện có, nhập khóa riêng tư vào tài khoản mới,
tạo tài khoản mới hoặc cập nhật tài khoản hiện có.
 ...
Khóa được lưu trữ dưới <DATADIR>/keystore.
Việc chuyển toàn bộ thư mục hoặc khóa riêng lẻ trong đó
giữa các nút Klaytn chỉ là sao chép đơn thuần.

Đảm bảo bạn sao lưu khóa thường xuyên.

CÁCH SỬ DỤNG:
   lệnh tài khoản ken [tùy chọn lệnh] [arguments...]

LỆNH:
     list    In tóm tắt các tài khoản hiện có
     new     Tạo tài khoản mới
     update  Cập nhật tài khoản hiện có
     import  Nhập khóa riêng tư vào tài khoản mới
```

```bash
$ ken init -h
init [tùy chọn lệnh] [arguments...]

Lệnh init khởi tạo một khối khởi nguyên mới và định nghĩa cho mạng lưới.
Đây là một hành động phá hoại và làm thay đổi mạng lưới mà bạn sẽ
tham gia vào.
 ...
```

## Bảng điều khiển JavaScript <a href="#javascript-console" id="javascript-console"></a>

Nút điểm cuối Klaytn đi kèm bảng điều khiển JavaScript. Từ dòng lệnh của bảng điều khiển, bạn có thể khởi tạo một phần của các lệnh gọi ra API Klaytn đến EN của mình. Để đính kèm vào bảng điều khiển JavaScript, hãy thực thi lệnh sau.

```bash
$ ken attach ~/kend_home/klay.ipc
Welcome to the Klaytn JavaScript console

!instance: Klaytn/vX.X.X/XXXX-XXXX/goX.X.X
 datadir: ~/kend_home
 modules: admin:1.0 debug:1.0 governance:1.0 istanbul:1.0 klay:1.0 miner:1.0 net:1.0 personal:1.0 rpc:1.0 txpool:1.0

 >
```

Lệnh `attach` kết nối với nút đang chạy, trong khi lệnh `console` khởi chạy một nút và kết nối với nút đó.

```bash
   attach      Bắt đầu một môi trường JavaScript tương tác (kết nối với nút)
   console     Bắt đầu một môi trường JavaScript tương tác
```

### API mô-đun <a href="#module-apis" id="module-apis"></a>

Nếu bạn nhập tên mô-đun trên dấu nhắc bảng điều khiển, bạn sẽ thấy các thuộc tính và chức năng có sẵn của mô-đun. Để biết chi tiết các chức năng, vui lòng tham khảo [API Klaytn](/content/dapp/json-rpc).

```javascript
> personal
{
  listAccounts: [...],
  listWallets: [...],
  deriveAccount: function(),
  ecRecover: function(),
  getListAccounts: function(callback),
  getListWallets: function(callback),
  importRawKey: function(),
  lockAccount: function(),
  ...
}

> personal.listAccounts
["0x960dba2500ab529693ef8e299210768aa0d55ec8", "0x09a04dc9ac3cd92de5ff0d45ae50ff1b618305d9", "0x36662211c072dadbf5fc1e087ddebd36df986abd", "0xbf9683cf04520eeba6d936a3478de29437c5d048"]
> 
```


# API JSON-RPC

Nút điểm cuối thể hiện các API JSON-RPC. Bạn có thể kích hoạt/vô hiệu hóa các API như sau. Để biết thông số API chi tiết, vui lòng tham khảo [API JSON-RPC](/content/dapp/json-rpc).

**LƯU Ý**: Việc cung cấp API qua giao diện HTTP (`rpc`) hoặc WebSocket (`ws`) sẽ cấp cho mọi người quyền truy cập vào các API có thể truy cập giao diện này (DApps, trình duyệt tab, v. v). Hãy thận trọng với những API bạn kích hoạt. Theo mặc định, Klaytn kích hoạt tất cả các API trên giao diện IPC (`ipc`) nhưng đối với `rpc` và `ws` các mô-đun bắt buộc phải được bật.

### Kích hoạt API <a href="#enabling-apis" id="enabling-apis"></a>

#### Từ dòng lệnh <a href="#from-commandline" id="from-commandline"></a>

Để cung cấp API qua các điểm cuối Klaytn RPC, vui lòng chỉ định chúng bằng đối số dòng lệnh `--${interface}api` trong đó `${interface}` có thể là `rpc` cho điểm cuối HTTP hoặc `ws` cho điểm cuối WebSocket.

`ipc` cung cấp tất cả các API trên ổ cắm unix (Unix) hoặc điểm cuối ống dẫn có tên (Windows) mà không có bất kỳ cờ nào.

Bạn có thể khởi chạy nút Klaytn với các API cụ thể mà bạn muốn thêm như ví dụ bên dưới. Nhưng hãy nhớ rằng bạn không thể thay đổi API sau khi khởi chạy nút.

Ví dụ) khởi chạy một nút Klaytn có bật các mô-đun `klay` và `net`:

```shell
$ ken --rpcapi klay,net --rpc --{other options}
```

Giao diện HTTP RPC phải được bật bằng cách sử dụng cờ báo `--rpc`.

#### Sử dụng cấu hình <a href="#using-configuration" id="using-configuration"></a>

Vui lòng cập nhật thuộc tính `RPC_ENABLE`, `RPC_API`, `WS_ENABLE` và `WS_API` trong [Tập tin cấu hình](/content/operation-guide/configuration).

### Truy vấn API đã kích hoạt <a href="#querying-enabled-apis" id="querying-enabled-apis"></a>

Để xác định API mà giao diện cung cấp, có thể gọi phương pháp `modules` JSON-RPC. Ví dụ: trên giao diện `rpc`:

**IPC**

```javascript
$ echo '{"jsonrpc":"2.0","method":"rpc_modules","params":[],"id":1}' | nc -U klay.ipc
```

**HTTP**

```shell
$ curl -H "Content-Type: application/json" --data '{"jsonrpc":"2.0","method":"rpc_modules","params":[],"id":1}' https://public-en-baobab.klaytn.net
```

sẽ cung cấp cho bạn tất cả các mô-đun đã kích hoạt bao gồm cả số phiên bản:

```
{
   "jsonrpc":"2.0",
   "id":1,
   "result":{
      "admin":"1.0",
      "debug":"1.0",
      "klay":"1.0",
      "miner":"1.0",
      "net":"1.0",
      "personal":"1.0",
      "rpc":"1.0",
      "txpool":"1.0",
      "web3":"1.0"
   }
}
```

### Disabling unsafe debug APIs <a href="#disabling-unsafe-debug-apis" id="disabling-unsafe-debug-apis"></a>

Some debug namespace APIs are unsafe/unappropriate to be opened to public. We recommend you to provide the debug namespace APIs to authorized users only. However, if you want to maintain a public EN and provide debug namespace APIs to the public, we strongly recommend you to set the `rpc.unsafe-debug.disable` flag which will disable APIs that are unsafe/unappropriate to be opened to the public and enable only a subset of the debug namespace APIs.

The enabled APIs are as follows:

* [VM Tracing](/content/dapp/json-rpc/api-references/debug/tracing) APIs, however with limited functionality (only [pre-defined tracers](/content/dapp/json-rpc/api-references/debug/tracing#tracing-options) are allowed)
* debug\_dumpBlock, debug\_dumpStateTrie, debug\_getBlockRlp, debug\_getModifiedAccountsByHash, debug\_getModifiedAccountsByNumber, debug\_getBadBlocks, debug\_getModifiedStorageNodesByNumber
* debug\_metrics

To set the `rpc.unsafe-debug.disable` flag, append the following line in the `kend.conf` file.

```
ADDITIONAL="$ADDITIONAL --rpc.unsafe-debug.disable"
```


# Core Cell

## Đối tượng mục tiêu <a href="#intended-audience" id="intended-audience"></a>

* Người vận hành Core Cell
* Nếu bạn muốn tạo và chạy Ứng dụng Blockchain trên Klaytn, bạn không cần phải duy trì Core Cell. Thay vào đó, bạn chỉ cần chạy [Nút điểm cuối](/content/installation-guide/deployment/endpoint-node) để ứng dụng của bạn có thể tương tác với mạng lưới Klaytn.

## Tổng quan về Core Cell <a href="#core-cell-overview" id="core-cell-overview"></a>

Core Cell (CC) là một thực thể tham gia vào quá trình đồng thuận đồng thời chịu trách nhiệm thực hiện các giao dịch và tạo khối. Core Cell (CC) của Klaytn bao gồm các thành phần sau.

* Nút đồng thuận (CN): Nút đồng thuận tham gia vào quá trình tạo khối.
* Nút proxy (PN): Nút proxy cung cấp giao diện cho mạng lưới. Nút proxy chuyển yêu cầu giao dịch đến Nút đồng thuận và truyền các khối xuống Nút điểm cuối.

Core Cell được khuyến nghị nên bao gồm 1 CN và hai PN hoặc nhiều hơn. Một CN kết nối với những CN khác trong Mạng lưới Core Cell để thực hiện đồng thuận. CN chỉ chấp nhận kết nối từ PN của nó trong cùng Core Cell để nhận yêu cầu giao dịch và truyền các khối đến mạng lưới. PN chỉ chấp nhận kết nối từ EN trong Mạng lưới nút điểm cuối.

![Tổng quan về Core Cell](/files/eAGT1brxfOMdYYKt2ccD)

| Tên | Mô tả                                                                                                                                                                                                                                                            | Bảo mật mạng lưới                                                                                                                                                                                                                                                                                        | Số lượng                                                |
| --- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------- |
| CN  | Nút tạo khối mới với Nút đồng thuận khác trong Mạng lưới Core Cell                                                                                                                                                                                               | Một mạng lưới bao gồm các CN được cấp quyền. (Yêu cầu kiểm soát truy cập IP).                                                                                                                                                                                                                            | 1 đơn vị                                                |
| PN  | <p>- Một nút gửi giao dịch nhận được từ Mạng lưới nút điểm cuối Klaytn đến CN.<br>- Nút này truyền các khối đã tạo đến Mạng lưới nút điểm cuối Klaytn.<br>- Nút này có thể mở rộng theo chiều ngang tùy thuộc vào số lượng EN trong Mạng lưới nút điểm cuối.</p> | <p>- Nút này được kết nối với CN trong Core Cell. IP và Cổng của nó được yêu cầu công khai để chấp nhận kết nối từ các nút Klaytn khác trên mạng Internet.<br>- Nút này có thể kết nối với các PN trong Core Cell khác thông qua bootnode.<br>- Nút này có thể kết nối với EN thông qua bootnode EN.</p> | Cần ít nhất 1 PN. 2 PN hoặc nhiều hơn được khuyến nghị. |


# Yêu cầu hệ thống

## Thông số H/W <a href="#h-w-specification" id="h-w-specification"></a>

Hiệu suất mạng lưới được đo lường dựa trên thông số kỹ thuật phần cứng kém nhất trong mạng lưới. Theo cấu trúc mạng lưới blockchain, chỉ có thể mở rộng quy mô theo chiều dọc (tăng dung lượng phần cứng). Do đó, tất cả các nút trong mạng lưới nên có phần cứng tốt nhất và ít nhất là có thông số kỹ thuật tương tự với nhau.

Nếu bạn tò mò về cơ sở của thông số kỹ thuật phần cứng này thì bài viết [Xác định thông số kỹ thuật phần cứng tối ưu cho người vận hành nút Klaytn](https://klaytn.foundation/node-operator-optimal-specs/) sẽ giúp bạn hiểu rõ hơn.

Các phần sau đây thể hiện các thông số kỹ thuật được đề xuất cho cả CN và PN.

### Máy chủ Bare-metal <a href="#bare-metal-server" id="bare-metal-server"></a>

| Danh mục | Thông số kỹ thuật                                                                                                                                                                             |
| -------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Máy chủ  | Hệ thống máy chủ Intel® [M50CYP1UR212](https://www.intel.sg/content/www/xa/en/products/sku/214842/intel-server-system-m50cyp1ur212/specifications.html)                                       |
| CPU      | Intel® Xeon 8358 2.60 GHz (32-core/64-thread)                                                                                                                                                 |
| Bộ nhớ   | 128GB (32GB \* 4)                                                                                                                                                                             |
| Lưu trữ  | Ổ cứng SSD 3TB (hoặc lớn hơn) (Dung lượng và cấu hình lưu trữ ưu tiên có thể khác nhau tùy thuộc vào kích thước dữ liệu chuỗi. Vui lòng tham khảo với Đội ngũ Klaytn để biết thêm thông tin.) |

Lưu ý rằng đây là thông số kỹ thuật phần cứng được đề xuất cho CN và PN, không phải là yêu cầu chính xác. Bất kỳ máy móc vật lý nào có cấu hình phần cứng tương tự đều có thể vận hành CN hoặc PN.

### VM đám mây <a href="#cloud-vm" id="cloud-vm"></a>

#### Thông số kỹ thuật khuyến nghị cho AWS <a href="#recommended-specification-for-aws" id="recommended-specification-for-aws"></a>

| Kiểu nút |     Mẫu     | vCPU | Bộ nhớ (GiB) | Dung lượng lưu trữ (GiB) | Tốc độ lưu trữ (IOPS) | Giá (Seoul, USD/giờ) |
| :------: | :---------: | :--: | :----------: | :----------------------: | :-------------------: | :------------------: |
|    CN    | m6i.8xlarge |  32  |      128     |     3.000 (Tối thiểu)    |         9.000         |         1,888        |
|    PN    | m6i.4xlarge |  16  |      64      |     3.000 (Tối thiểu)    |         9.000         |         0,944        |

Thông số lưu trữ này bắt nguồn từ thông số của AWS EBS SSD (gp3).

Thông tin trên được lấy từ <https://aws.amazon.com/ec2/instance-types/> và [https://aws.amazon.com/ec2/pricing/on-demand/ ](https://aws.amazon.com/ec2/pricing/on-demand/)và có thể được AWS thay đổi.

#### Thông số kỹ thuật khuyến nghị cho Azure <a href="#recommended-specification-for-azure" id="recommended-specification-for-azure"></a>

| Kiểu nút |   Mẫu   | vCPU | Bộ nhớ (GiB) | Loại lưu trữ (GiB) | Tốc độ lưu trữ (IOPS) | Giá (Trung tâm Hàn Quốc, USD/giờ) |
| :------: | :-----: | :--: | :----------: | :----------------: | :-------------------: | :-------------------------------: |
|    CN    | D32s v5 |  32  |      128     |     P50 (4096)     |          7500         |               1,888               |
|    PN    | D16s v5 |  16  |      64      |     P50 (4096)     |          7500         |               0,944               |

Thông số lưu trữ này bắt nguồn từ thông số của Ổ Đĩa Azure Cao Cấp.

Thông tin trên được lấy từ <https://azure.microsoft.com/en-us/pricing/details/virtual-machines/series/> và <https://azure.microsoft.com/en-us/pricing/details/managed-disks/#pricing> và có thể được Microsoft thay đổi.

## Yêu cầu lưu trữ <a href="#storage-requirements" id="storage-requirements"></a>

Giả sử trung bình 100 TPS, kích thước giao dịch trung bình 300 byte và độ trễ khối 1 giây, yêu cầu dung lượng dự kiến hàng ngày là khoảng 2,5 GB/ngày (=300x100x86400).

## Hệ điều hành <a href="#operating-system" id="operating-system"></a>

Nên dùng môi trường tương thích với RHEL (7.8 trở lên). Nhị phân Klaytn đã được thử nghiệm đầy đủ trên Amazon Linux 2 nhưng chúng cũng có thể hoạt động trên các môi trường chạy trên linux khác. nhị phân macOS cũng được cung cấp cho mục đích phát triển.


# Cấu hình mạng

Core Cell có thể được tạo thành từ:

* nhiều mạng con (khuyến nghị)
* mạng con đơn lẻ

## Core Cell với nhiều mạng con <a href="#a-core-cell-with-multiple-subnets" id="a-core-cell-with-multiple-subnets"></a>

Nên dùng mạng con hai lớp được sử dụng trong các dịch vụ web chung như DB + AppServer và Máy chủ Web Proxy. Thiết kế mạng con này có nhiều ưu điểm hơn về bảo mật.

Vì các máy chủ giám sát cũng được yêu cầu để quản lý tất cả các máy chủ như một lớp khác, nên phần sau đây mô tả cách thiết lập một Core Cell với mạng con ba lớp.

Mạng con ba lớp bao gồm những phần sau:

* Mạng con CN
* Mạng con PN
* Mạng con quản lý (QL)

### Mạng con CN <a href="#cn-subnet" id="cn-subnet"></a>

Mạng con CN gồm máy chủ CN trong Core Cell. CN hoạt động trong một Core Cell là duy nhất nhưng nên chuẩn bị nút dự phòng để đảm bảo tính sẵn sàng cao. Địa chỉ IP/Cổng của tất cả CN trong Mạng lưới Core Cell (CCN) phải được mở cùng nhau vì chúng kết nối với nhau từ bên ngoài Core Cell. (Có thể nhận thông tin kết nối này từ các nhà vận hành Baobab.) Việc giao tiếp nội bộ với các mạng con khác trong Core Cell yêu cầu mở cổng mặc định (32323: số cổng Klaytn P2P mặc định) để kết nối với các PN của Mạng con PN. Ngoài ra, cần mở các cổng khác như cổng giám sát CN (61001) cho máy chủ giám sát và cổng SSH (22) cho mục đích quản lý. Nếu sử dụng tính năng đa kênh, cần mở thêm cổng khác (32324: cổng đa kênh mặc định).

![Mạng con CN](/files/uKRjtucxXfF5wa5TsIVB)

| Mạng con gốc | Mạng con mục tiêu    | Ingress                        | Egress |
| ------------ | -------------------- | ------------------------------ | ------ |
| Mạng con CN  | Mạng con PN          | P2P: 32323 (32324 cho đa kênh) | Tất cả |
| Mạng con CN  | Mạng con QL          | SSH: 22, Giám sát: 61001       | Tất cả |
| Mạng con CN  | Công khai (Internet) | IP và cổng P2P của mỗi CN      | Tất cả |

### Mạng con PN <a href="#pn-subnet" id="pn-subnet"></a>

Mạng con PN bao gồm máy chủ PN để cung cấp dịch vụ nhằm kết nối với EN bên ngoài.

Mạng con PN kết nối với các nút sau:

* CN trong Core Cell
* Một vài PN của Core Cell khác
* Máy chủ quản lý Core Cell (QL, Giám sát)
* Nút EN

![Mạng con PN](/files/YvxSzPMqcoeCsNkUq8Si)

| Mạng con gốc | Mạng con mục tiêu    | Ingress                        | Egress |
| ------------ | -------------------- | ------------------------------ | ------ |
| Mạng con PN  | Mạng con CN          | P2P: 32323 (32324 cho đa kênh) | Tất cả |
| Mạng con PN  | Mạng con QL          | SSH: 22, Giám sát: 61001       | Tất cả |
| Mạng con PN  | Công khai (Internet) | P2P: 32323                     | Tất cả |

### Mạng con QL <a href="#mgmt-subnet" id="mgmt-subnet"></a>

Mạng con QL là mạng con cổng cho người vận hành tham gia vào nút Core Cell thông qua ssh. Có thể cần máy chủ VPN để tạo kết nối cùng với máy chủ giám sát và máy chủ quản lý được cài đặt công cụ để quản lý các nút Core Cell.

![Mạng con quản lý](/files/QlqvY1UClcWrrcMyNwSm)

| Mạng con gốc | Mạng con mục tiêu    | Ingress                         | Egress |
| ------------ | -------------------- | ------------------------------- | ------ |
| Mạng con QL  | Mạng con CN          | Tất cả                          | Tất cả |
| Mạng con QL  | Mạng con PN          | Tất cả                          | Tất cả |
| Mạng con QL  | Công khai (Internet) | VPN (tcp): 443, VPN (udp): 1194 | Tất cả |

## Core Cell với mạng con đơn lẻ <a href="#a-core-cell-with-a-single-subnet" id="a-core-cell-with-a-single-subnet"></a>

Một mạng con đơn lẻ của Core Cell được xây dựng cho mục đích phát triển/thử nghiệm hoặc để tạo nhiều mạng con trong các trường hợp khó khăn.

Tất cả các nút được thiết lập dưới một mạng con CC đơn lẻ. Cần thiết lập tường lửa để kết nối CN với các CN khác trong Mạng lưới CN bằng cổng P2P (32323, 32324 cho tùy chọn đa kênh). Cổng P2P của PN được mở để kết nối với EN trong Mạng lưới nút điểm cuối (ENN) và PN trong Mạng lưới Core Cell (CNN). Ngoài ra, cần có một VPN tùy chọn và các máy chủ giám sát để quản lý từ xa.

![CC với mạng con đơn lẻ](/files/bVzYxAYMNLqV2ZtvtkbT)


# Hướng dẫn cài đặt


# Tải xuống

Bạn có thể tải về các gói cho CN và PN tại [trang tải về](/content/installation-guide/deployment/download).


# Trước khi cài đặt

Trước khi cài đặt gói Klaytn, bạn cần tạo thông tin nút liên kết để đăng ký URI nút. Gói Kgen được cấp cho người vận hành CC, vui lòng làm theo tuần tự các bước bên dưới.

1. Gói tải về `kgen`
2. Node Key & Node URI Creation
3. Đăng ký URI nút

## Gói tải về `kgen` <a href="#download-kgen-package" id="download-kgen-package"></a>

Đầu tiên, bạn cần tải về phiên bản mới nhất của gói `kgen` tùy thuộc vào hệ điều hành của bạn ở trang [Tải xuống](/content/installation-guide/deployment/core-cell/installation-guide/download).

Bạn có thể tìm tập tin nhị phân `kgen`trong thư mục `bin`.

## Node Key & Node URI Creation <a href="#node-key-node-uri-creation" id="node-key-node-uri-creation"></a>

Khóa nút và URI nút chỉ được tạo một lần khi bắt đầu. URI nút phải được chia sẻ với các Core Cell khác trong Mạng lưới Core Cell. Một CN kết nối với các CN khác còn một PN kết nối với một CN và vài PN bằng URI nút đã tạo. URI nút được tạo dựa trên khóa nút bằng `kgen`. đã tải về. Dòng lệnh dưới đây tạo `khóa nút` và `node_info.json`.

`kgen` lấy IP và số Cổng liên kết như sau.

```
$ kgen --ip "123.456.789.012" --port 32323 --file
$ ls
nodekey node_info.json
```

`Khóa nút` là chuỗi thập lục phân 64 byte, cũng là khóa riêng tư được sử dụng nội bộ trong nút. Khóa riêng tư này phải có trong thư mục dữ liệu Klaytn và bạn nên cẩn thận, đừng để làm mất nó.

```
$ cat nodekey
f08f2118c455a6c9c9b5e035d3571e570a719ea61771e268546e796a264acc2b
$ mv nodekey ~/kcnd_home
```

Tập tin `node_info.json` được tạo bao gồm các nội dung sau.

| Tên khoá    | Mô tả                        | Ví dụ                                                                                                                                                                  |
| ----------- | ---------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| NodeAddress | địa chỉ của một nút liên kết | 0xc8a23d67f2471066fa1b07270651fea7e5c0cf78                                                                                                                               |
| Khóa nút    | khóa nút (hay khóa riêng tư) | aaa7248dfdf19418ae9121a0f39db39c5c27a3e404ea7c1b8e020ca8dbe7e71a                                                                                                         |
| NodeURI     | URI nút                      | kni://4f2f47f3bf35a2c576d3345e6e9c49b147d510c05832d2458709f63c3c90c76ead205975d944ed65e77dd4c6f63ebe1ef21d60da95952bc1e200e7487f4d9e1b\@123.456.789.012:32323?discport=0 |

`node_info.json` chứa thông tin nút trong định dạng JSON như sau.

```
$ cat node_info.json
{
    "NodeAddress": "0xc8a23d67f2471066fa1b07270651fea7e5c0cf78",
    "NodeKey": "aaa7248dfdf19418ae9121a0f39db39c5c27a3e404ea7c1b8e020ca8dbe7e71a",
    "NodeURI": "kni://4f2f47f3bf35a2c576d3345e6e9c49b147d510c05832d2458709f63c3c90c76ead205975d944ed65e77dd4c6f63ebe1ef21d60da95952bc1e200e7487f4d9e1b@123.456.789.012:32323?discport=0"
}
```

## Đăng ký URI nút <a href="#node-uri-enrollment" id="node-uri-enrollment"></a>

URI nút được tạo nên được đăng ký để tham gia Mạng lưới Core Cell (CCN). Quá trình đăng ký sẽ diễn ra như sau.

1. Tạo một URI nút bằng`kgen` (`node_info.json`) có chứa IP và số Cổng liên kết.
2. Gửi thông tin đến địa chỉ email chính thức của Klaytn (`bootstrap@klaytn.com` cho Cypress hoặc `baobab@klaytn.com` cho Baobab).

Thông tin đăng ký cần được gửi đến địa chỉ email chính thức của Klaytn. Định dạng sẽ như sau.

Trong trường hợp CN,

```
Công ty: Kakao
URI CN : kni://
4f2f47f3bf35a2c576d3345e6e9c49b147d510c05832d2458709f63c3c90c76ead205975d944ed65e77dd4c6f63ebe1ef21d60da95952bc1e200e7487f4d9e1b@123.456.789.012:32323?discport=0
```

Trong trường hợp PN,

```
Công ty: Kakao
URI PN : kni://
4f2f47f3bf35a2c576d3345e6e9c49b147d510c05832d2458709f63c3c90c76ead205975d944ed65e77dd4c6f63ebe1ef21d60da95952bc1e200e7487f4d9e1b@123.456.789.012:32323?discport=0
```


# Thiết lập nút đồng thuận


# Hướng dẫn cài đặt

Bạn có thể tải về phiên bản mới nhất của `kcn` trên trang [Tải xuống](/content/installation-guide/deployment/core-cell/installation-guide/download).

## Phân bổ lưu trữ Linux <a href="#linux-archive-distribution" id="linux-archive-distribution"></a>

Tập tin lưu trữ bao gồm tập tin nhị phân thực thi và cấu hình có cấu trúc như sau.

**Lưu ý**: KHÔNG thay đổi cấu trúc hoặc tên tập tin. Nếu bạn thay đổi điều đó, nút có thể sẽ không hoạt động đúng.

```
- bin
  |- kcn
  |- kcnd
- conf
  |- kcnd.conf
```

| Tên tập tin    | Mô tả tập tin                    |
| -------------- | -------------------------------- |
| bin/kcn        | Tập tin thực thi CN              |
| bin/kcnd       | Tập tin lệnh bắt đầu/kết thúc CN |
| conf/kcnd.conf | Tập tin cấu hình CN              |

### Cài đặt <a href="#installation" id="installation"></a>

Quá trình cài đặt chính là giải nén gói đã tải về tại nơi bạn muốn cài đặt gói.

```bash
$ tar zxf kcn-vX.X.X-linux-amd64.tar.gz
```

Hoặc,

```bash
$ tar zxf kcn-baobab-vX.X.X-linux-amd64.tar.gz
```

**Lưu ý**: nên thêm đường dẫn thư mục chưa giải nén `kcn-linux-amd64/bin` vào biến môi trường `$PATH` để chạy `kcn` và `kcnd` trên toàn hệ thống. Ví dụ,

```bash
$ export PATH=$PATH:~/downloaded/path/kcn-linux-amd64/bin
```

Các phần khác giả định rằng đường dẫn đã được thêm vào biến.

## Phân bổ RPM (RHEL/CentOS/Fedora) <a href="#rpm-rhel-centos-fedora" id="rpm-rhel-centos-fedora"></a>

### Cài đặt RPM đã tải về <a href="#install-downloaded-rpm" id="install-downloaded-rpm"></a>

Bạn có thể cài đặt RPM đã tải về với lệnh `yum` sau đây.

```bash
$ yum install kcnd-vX.X.X.el7.x86_64.rpm
```

Hoặc,

```bash
$ yum install kcnd-baobab-vX.X.X.el7.x86_64.rpm
```

### Cài đặt từ Klaytn Yum Repo <a href="#install-from-klaytn-yum-repo" id="install-from-klaytn-yum-repo"></a>

Ngoài ra, bạn có thể cài đặt `kcnd` từ Klaytn Yum repo, chạy:

```bash
$ sudo curl -o /etc/yum.repos.d/klaytn.repo https://packages.klaytn.net/config/rhel/7/prod.repo && sudo yum install kcnd
```

### Vị trí đã cài đặt <a href="#installed-location" id="installed-location"></a>

Tập tin đã cài đặt nằm ở vị trí như sau.

| Tên tập tin | Vị trí                   |
| ----------- | ------------------------ |
| kcn         | /usr/bin/kcn             |
| kcnd.conf   | /etc/kcnd/conf/kcnd.conf |


# Cấu hình

Cấu hình CN dùng để tạo thư mục dữ liệu và thiết lập các giá trị trong tập tin cấu hình `kcnd.conf`.

1. Tạo thư mục dữ liệu CN.
2. Cài đặt khóa nút
3. Định cấu hình CN với `kcnd.conf`.

## Tạo thư mục dữ liệu CN <a href="#cn-data-directory-creation" id="cn-data-directory-creation"></a>

Kích thước của dữ liệu blockchain Klaytn sẽ luôn tăng lên thế nên cần sử dụng một dung lượng lưu trữ đủ lớn. Bạn có thể cần phải tạo thư mục trên đường dẫn bạn muốn.

```bash
$ mkdir -p /var/kcnd/data
```

## Cài đặt Khóa nút <a href="#install-node-key" id="install-node-key"></a>

Để vận hành CN cần có `khóa nút`. Nhị phân KCN sẽ tạo ra một nút mới nếu bạn không có sẵn. Nếu bạn đã có, bạn cần chuyển `khóa nút` vào thư mục dữ liệu CN. Cách để tạo `khóa nút` được mô tả trong phần '[Trước khi bạn cài đặt](/content/installation-guide/deployment/core-cell/installation-guide/before-you-install)'. Dòng lệnh sau sao chép`khóa nút` vào thư mục dữ liệu CN.

```bash
$ cp nodekey /var/kcnd/data
```

## Cập nhật Tập tin cấu hình <a href="#update-the-configuration-file" id="update-the-configuration-file"></a>

Vị trí tập tin cấu hình:

* Nếu phân bổ lưu trữ, vị trí thư mục cấu hình mặc định là `$INSTALL_PATH/kcn-linux-amd64/conf/`.
* Nếu phân bổ gói, vị trí thư mục cấu hình mặc định là `/etc/kpnd/conf/`.

### Thêm Thư mục dữ liệu <a href="#add-data-directory" id="add-data-directory"></a>

Bạn nên cập nhật biến môi trường thư mục dữ liệu `$DATA_DIR`trên tập tin cấu hình `kcnd.conf`.

```
...
DATA_DIR=/var/kcnd/data
...
```

### Thiếp lập Rewardbase <a href="#setup-rewardbase" id="setup-rewardbase"></a>

Người vận hành CN sẽ nhận được KLAY như phần thưởng của việc tham gia vào đồng thuận mạng lưới Klaytn. Vì lý do này, cần phải thiết lập một địa chỉ trên tập tin cấu hình `kcnd.conf`.

Có nhiều cách để tạo tài khoản mới nhưng `kcn` cũng cung cấp các chức năng. Bạn có thể xem tin nhắn trợ giúp bằng lệnh sau.

```bash
$ kcn tài khoản new --help
```

Một trong những ví dụ về việc thực quy trình này như sau. Trước hết, bạn cần tạo một tài khoản mới để gửi phần thưởng KLAY đến.

```bash
$ kcn tài khoản new --datadir ~/kcnd_home
INFO[03/15,09:04:43 +09] [17] Setting connection type                   nodetype=cn conntype=-0
INFO[03/15,09:04:43 +09] [17] Maximum peer count                        KLAY=25 LES=0 total=25
INFO[03/15,09:04:43 +09] [17] SBN is disabled.
Tài khoản mới của bạn được khóa bằng mật khẩu. Vui lòng nhập mật khẩu. Đừng quên mật khẩu này.
Cụm mật khẩu:
Nhắc lại cụm mật khẩu:
Địa chỉ: {d13f7da0032b1204f77029dc1ecbf4dae2f04241}
```

Sau đó, lưu trữ khóa liên kết sẽ được tạo trên đường dẫn bạn đã xác định. Tiếp theo, bạn cần cho địa chỉ đã tạo vào tập tin `kcnd.conf` như sau.

```
...
REWARDBASE="d13f7da0032b1204f77029dc1ecbf4dae2f04241"
...
```

Hãy nhớ rằng lưu trữ khóa và mật khẩu mà bạn đã tạo là vô cùng quan trọng. Do đó, bạn phải quản lý chúng thật cẩn thận. Xem thêm thông tin về `kcnd.conf` trên phần [Tập tin cấu hình](/content/operation-guide/configuration).

## Đồng bộ nhanh (Tùy chọn) <a href="#fast-sync-optional" id="fast-sync-optional"></a>

Mỗi CN duy trì một bản sao dữ liệu chuỗi của mạng lưới. Nếu một nút không được đồng bộ, nút này có thể lấy dữ liệu này từ các nút khác trong mạng lưới -- một quá trình được gọi là đồng bộ hóa. Khi một CN mới được bắt đầu lần đầu tiên, nó phải tải xuống toàn bộ dữ liệu chuỗi từ mạng lưới.

Để đẩy nhanh quá trình này, bạn cần thực hiện đồng bộ nhanh bằng cách tải về bản thu thập dữ liệu của dữ liệu chuỗi trước khi bắt đầu CN. Điều này giúp giảm đáng kể thời gian CN cần để đồng bộ khi bắt đầu lần đầu tiên.

Tải xuống bản thu thập dữ liệu chuỗi mới nhất từ [Lưu trữ thu thập dữ liệu Cypress](http://packages.klaytn.net/cypress/chaindata/) hoặc[Lưu trữ thu thập dữ liệu Baobab](http://packages.klaytn.net/baobab/chaindata/). Trước khi bắt đầu `kcnd`, trích xuất bản thu thập dữ liệu trong DATA\_DIR mà bạn định cấu hình trong `kcnd.conf`.

Ví dụ:

```bash
$ tar -C ~/kcnd_home -xvf klaytn-cypress-chaindata-latest.tar.gz
```

Hoặc,

```bash
$ tar -C ~/kcnd_home -xvf klaytn-baobab-chaindata-latest.tar.gz
```

Sau khi dữ liệu được trích xuất, bạn có thể bắt đầu CN như bình thường.

Bạn có thể tham khảo thông tin chi tiết tại [Thay đổi dữ liệu chuỗi](/content/operation-guide/chaindata-change)


# Khởi động CN

## Bắt đầu/Dừng CN <a href="#cn-start-stop" id="cn-start-stop"></a>

Bạn có thể bắt đầu/dừng dịch vụ Klaytn bằng lệnh `systemctl` sau đây.

**Lưu ý**: Việc này yêu cầu quyền root.

**bắt đầu**

```bash
$ systemctl start kcnd.service

```

**dừng**

```bash
$ systemctl stop kcnd.service

```

**trạng thái**

```bash
$ systemctl trạng thái kcnd.service

```

## Khắc phục sự cố <a href="#troubleshooting" id="troubleshooting"></a>

Nếu bạn gặp lỗi sau,

```bash
Không thể bắt đầu kcnd.service: Không tìm thấy đơn vị.
```

tải lại cấu hình trình quản lý hệ thống bằng lệnh sau.

```bash
$ systemctl daemon-reload
```


# Thiết lập nút proxy


# Hướng dẫn cài đặt

Bạn có thể tải về phiên bản mới nhất của `kpn` trên trang [Tải xuống](/content/installation-guide/deployment/core-cell/installation-guide/download).

## Phân bổ lưu trữ Linux <a href="#linux-archive-distribution" id="linux-archive-distribution"></a>

Tập tin lưu trữ bao gồm tập tin nhị phân thực thi và cấu hình có cấu trúc như sau.

**Lưu ý**: KHÔNG thay đổi cấu trúc hoặc tên tập tin. Nếu bạn thay đổi điều đó, nút có thể sẽ không hoạt động đúng.

```
- bin
  |- kpn
  |- kpnd
- conf
  |- kpnd.conf
```

| Tên tập tin    | Mô tả tập tin                    |
| -------------- | -------------------------------- |
| bin/kpn        | Tập tin thực thi PN              |
| bin/kpnd       | Tập tin lệnh bắt đầu/kết thúc PN |
| conf/kpnd.conf | Tập tin cấu hình PN              |

### Cài đặt <a href="#installation" id="installation"></a>

Quá trình cài đặt chính là giải nén gói đã tải về tại nơi bạn muốn cài đặt gói.

```bash
$ tar zxf kpn-vX.X.X-linux-amd64.tar.gz
```

Hoặc,

```bash
$ tar zxf kpn-baobab-vX.X.X-linux-amd64.tar.gz
```

**Lưu ý**: nên thêm đường dẫn thư mục chưa giải nén `kcn-linux-amd64/bin` vào biến môi trường `$PATH` để chạy `kcn` và `kcnd` trên toàn hệ thống. Ví dụ,

```bash
$ export PATH=$PATH:~/downloaded/path/kpn-linux-amd64/bin
```

Các phần khác giả định rằng đường dẫn đã được thêm vào biến.

## Phân bổ RPM (RHEL/CentOS/Fedora) <a href="#rpm-rhel-centos-fedora" id="rpm-rhel-centos-fedora"></a>

### Cài đặt RPM đã tải về <a href="#install-downloaded-rpm" id="install-downloaded-rpm"></a>

Bạn có thể cài đặt RPM đã tải về với lệnh `yum` sau đây.

```bash
$ yum install kpnd-vX.X.X.el7.x86_64.rpm
```

Hoặc,

```bash
$ yum install kpnd-baobab-vX.X.X.el7.x86_64.rpm
```

### Cài đặt từ Klaytn Yum Repo <a href="#install-from-klaytn-yum-repo" id="install-from-klaytn-yum-repo"></a>

Ngoài ra, bạn có thể cài đặt `kpnd` từ Klaytn Yum repo, chạy:

```bash
$ sudo curl -o /etc/yum.repos.d/klaytn.repo https://packages.klaytn.net/config/rhel/7/prod.repo && sudo yum install kpnd
```

### Vị trí đã cài đặt <a href="#installed-location" id="installed-location"></a>

Tập tin đã cài đặt nằm ở vị trí như sau.

| Tên tập tin | Vị trí                   |
| ----------- | ------------------------ |
| kpn         | /usr/bin/kpn             |
| kpnd.conf   | /etc/kpnd/conf/kpnd.conf |


# Cấu hình

Cấu hình PN dùng để tạo thư mục dữ liệu và thiết lập các giá trị trong tập tin cấu hình `kpnd.conf`.

1. Tạo thư mục dữ liệu PN
2. Cài đặt khóa nút
3. Cài đặt `static-node.json`
4. Định cấu hình PN với `kpnd.conf`.

## Tạo thư mục dữ liệu PN <a href="#pn-data-directory-creation" id="pn-data-directory-creation"></a>

Kích thước của dữ liệu blockchain Klaytn sẽ luôn tăng lên thế nên cần sử dụng một dung lượng lưu trữ đủ lớn. Bạn có thể cần phải tạo thư mục trên đường dẫn bạn muốn.

```bash
$ mkdir -p /var/kpnd/data
```

## Cài đặt Khóa nút <a href="#install-node-key" id="install-node-key"></a>

Để vận hành PN cần có `khóa nút`. Nhị phân PN Klaytn sẽ tạo ra một nút mới nếu bạn không có sẵn. Nếu bạn đã có, bạn cần chuyển `khóa nút` vào thư mục dữ liệu PN. Cách để tạo `khóa nút` được mô tả trong phần '[Trước khi bạn cài đặt](/content/installation-guide/deployment/core-cell/installation-guide/before-you-install)'. Dòng lệnh sau sao chép `khóa nút` vào thư mục dữ liệu PN.

```bash
$ cp nodekey /var/kpnd/data
```

## Cài đặt `static-nodes.json` <a href="#install-static-nodes-json" id="install-static-nodes-json"></a>

`static-nodes.json` nên được tạo bởi người vận hành PN. Nó chứa các địa chỉ kết nối với PN của bạn. Bạn nên thêm địa chỉ bao gồm CN và PN từ Core Cell khác. Vui lòng liên hệ qua email chính thức của Klaytn để biết thêm chi tiết (`bootstrap@klaytn.com` cho Cypress hoặc `baobab@klaytn.com` cho Baobab).

**static-nodes.json**

```
[
  "kni://4f2f47f3bf35a2c576d3345e6e9c49b147d510c05832d2458709f63c3c90c76ead205975d944ed65e77dd4c6f63ebe1ef21d60da95952bc1e200e7487f4d9e1b@10.11.2.101:32323?discport=0&ntype=cn",
  "kni://8dee912aeda2ccfaa4fe421f015d4d75c2e3fd4aab75fa399b42767caad33531e57f3356b4a4af374593e33ec4320e1325aa2390a7be2489fa6b5724894680eb@10.11.2.102:32323?discport=0&ntype=pn"
]
```

URI nút của PN có trong phần '[Trước khi bạn cài đặt](/content/installation-guide/deployment/core-cell/installation-guide/before-you-install)'. (Lưu ý: Địa chỉ IP này khác với IP công khai của CN.) Dòng lệnh sau sao chép tập tin `static-nodes.json` vào thư mục dữ liệu PN.

```bash
$ cp static-nodes.json /var/kpnd/data
```

## Cập nhật Tập tin cấu hình <a href="#update-the-configuration-file" id="update-the-configuration-file"></a>

Vị trí tập tin cấu hình:

* Nếu phân bổ lưu trữ, vị trí thư mục cấu hình mặc định là `$INSTALL_PATH/kpn-linux-amd64/conf/`.
* Nếu phân bổ gói, vị trí thư mục cấu hình mặc định là `/etc/kpnd/conf/`.

### Thêm Thư mục dữ liệu <a href="#add-data-directory" id="add-data-directory"></a>

Bạn nên cập nhật biến môi trường thư mục dữ liệu `$DATA_DIR`trên tập tin cấu hình `kpnd.conf`.

```
...
DATA_DIR=/var/kpnd/data
...
```

## Đồng bộ nhanh (Tùy chọn) <a href="#fast-sync-optional" id="fast-sync-optional"></a>

Mỗi PN duy trì một bản sao dữ liệu chuỗi của mạng lưới. Nếu một nút không được đồng bộ, nút này có thể lấy dữ liệu này từ các nút khác trong mạng lưới -- một quá trình được gọi là đồng bộ hóa. Khi một PN mới được bắt đầu lần đầu tiên, nó phải tải xuống toàn bộ dữ liệu chuỗi từ mạng lưới.

Để đẩy nhanh quá trình này, bạn cần thực hiện đồng bộ nhanh bằng cách tải về bản thu thập dữ liệu của dữ liệu chuỗi trước khi bắt đầu PN. Điều này giúp giảm đáng kể thời gian PN cần để đồng bộ khi bắt đầu lần đầu tiên.

Tải xuống bản thu thập dữ liệu chuỗi mới nhất từ [Lưu trữ thu thập dữ liệu Cypress](http://packages.klaytn.net/cypress/chaindata/) hoặc[Lưu trữ thu thập dữ liệu Baobab](http://packages.klaytn.net/baobab/chaindata/). Trước khi bắt đầu `kpnd`, trích xuất bản thu thập dữ liệu trong DATA\_DIR mà bạn định cấu hình trong `kpnd.conf`.

Ví dụ:

```
$ tar -C /var/kpnd/data -xvf klaytn-cypress-chaindata-latest.tar.gz
```

Hoặc,

```
$ tar -C /var/kpnd/data -xvf klaytn-baobab-chaindata-latest.tar.gz
```

Sau khi dữ liệu được trích xuất, bạn có thể bắt đầu PN như bình thường.

Bạn có thể tham khảo thông tin chi tiết tại [Thay đổi dữ liệu chuỗi](https://github.com/klaytn/klaytn-docs-vn/blob/main/docs/operation-guide/chaindata-change/README.md)


# Khởi động PN

## Bắt đầu/Dừng PN <a href="#pn-start-stop" id="pn-start-stop"></a>

Bạn có thể bắt đầu/dừng dịch vụ Klaytn bằng lệnh `systemctl` sau đây.

**Lưu ý**: Việc này yêu cầu quyền root.

**bắt đầu**

```bash
$ systemctl start kpnd.service

```

**dừng**

```bash
$ systemctl stop kpnd.service

```

**trạng thái**

```bash
$ systemctl trạng thái kpnd.service

```

## Khắc phục sự cố <a href="#troubleshooting" id="troubleshooting"></a>

Nếu bạn gặp lỗi sau,

```bash
Không thể bắt đầu kpnd.service: Không tìm thấy đơn vị.
```

tải lại cấu hình trình quản lý hệ thống bằng lệnh sau.

```bash
$ systemctl daemon-reload
```


# Kiểm tra Core Cell

Đã đến lúc kiểm tra xem Core Cell đã được cài đặt thành công chưa và nó có hoạt động như mong đợi sau khi cài đặt không.

## Tình trạng xử lý <a href="#process-status" id="process-status"></a>

Có thể kiểm tra trạng thái quy trình của CN/PN bằng các lệnh trạng thái `systemctl` và `kcnd/kpnd`.

### systemctl <a href="#systemctl" id="systemctl"></a>

`systemctl` được cài đặt cùng với RPM, có thể kiểm tra trạng thái của CN/PN như sau.

```bash
$ systemctl trạng thái kcnd.service
● kcnd.service - (null)
   Loaded: loaded (/etc/rc.d/init.d/kcnd; bad; vendor preset: disabled)
   Active: active (running) since Wed 2019-01-09 11:42:39 UTC; 1 months 4 days ago
     Docs: man:systemd-sysv-generator(8)
  Process: 29636 ExecStart=/etc/rc.d/init.d/kcnd start (code=exited, trạng thái=0/SUCCESS)
 Main PID: 29641 (kcn)
   CGroup: /system.slice/kcnd.service
           └─29641 /usr/local/bin/kcn --networkid 1000 --datadir /kcnd_home --port 32323 --srvtype fasthttp --metrics --prometheus --verbosity 3 --txpool.global...

Jan 09 11:42:39 ip-10-11-2-101.ap-northeast-2.compute.internal systemd[1]: Starting (null)...
Jan 09 11:42:39 ip-10-11-2-101.ap-northeast-2.compute.internal kcnd[29636]: Starting kcnd: [  OK  ]
Jan 09 11:42:39 ip-10-11-2-101.ap-northeast-2.compute.internal systemd[1]: Started (null).
```

Bạn có thể kiểm tra trạng thái hiện tại như `Active: active (running)` trong ví dụ trên.

### kcnd (kpnd) <a href="#kcnd-kpnd" id="kcnd-kpnd"></a>

`kcnd` (hoặc `kpnd`) được cài đặt cùng với gói và trạng thái của CN/PN có thể được kiểm tra như sau.

```bash
$ kcnd trạng thái
kcnd is running
```

## Nhật ký <a href="#logs" id="logs"></a>

Nhật ký được lưu ở `kcnd.out` (hoặc `kpnd.out`) tại đường dẫn xác định trong trường `LOG_DIR` của tập tin `kcnd.conf` (hoặc `kpnd.conf`). Khi nút hoạt động bình thường, bạn có thể thấy rằng mỗi giây sẽ có một khối được tạo như sau.

Ví dụ:

```bash
$ tail kcnd.out
INFO[02/13,07:02:24 Z] [35] Commit new mining work                    number=11572924 txs=0 elapsed=488.336µs
INFO[02/13,07:02:25 Z] [5] Imported new chain segment                blocks=1 txs=0 mgas=0.000     elapsed=1.800ms   mgasps=0.000       number=11572924 hash=f46d09…ffb2dc cache=1.59mB
INFO[02/13,07:02:25 Z] [35] Commit new mining work                    number=11572925 txs=0 elapsed=460.485µs
INFO[02/13,07:02:25 Z] [35] 🔗 block reached canonical chain           number=11572919 hash=01e889…524f02
INFO[02/13,07:02:26 Z] [14] Committed                                 address=0x1d4E05BB72677cB8fa576149c945b57d13F855e4 hash=1fabd3…af66fe number=11572925
INFO[02/13,07:02:26 Z] [5] Imported new chain segment                blocks=1 txs=0 mgas=0.000     elapsed=1.777ms   mgasps=0.000       number=11572925 hash=1fabd3…af66fe cache=1.59mB
INFO[02/13,07:02:26 Z] [35] Commit new mining work                    number=11572926 txs=0 elapsed=458.665µs
INFO[02/13,07:02:27 Z] [14] Committed                                 address=0x1d4E05BB72677cB8fa576149c945b57d13F855e4 hash=60b9aa…94f648 number=11572926
INFO[02/13,07:02:27 Z] [5] Imported new chain segment                blocks=1 txs=0 mgas=0.000     elapsed=1.783ms   mgasps=0.000       number=11572926 hash=60b9aa…94f648 cache=1.59mB
INFO[02/13,07:02:27 Z] [35] Commit new mining work                    number=11572927 txs=0 elapsed=483.436µs
```

## bảng điều khiển kcn (bảng điều khiển kpn) <a href="#kcn-console-kpn-console" id="kcn-console-kpn-console"></a>

Klaytn cung cấp một CLI khách: `bảng điều khiển kpn` (hoặc `bảng điều khiển kpn`). Tuy nhiên, CN/PN có thể vô hiệu hóa giao diện RPC cho máy khách vì lý do bảo mật. Một cách khác để sử dụng máy khách là kết nối với quy trình thông qua IPC (giao tiếp giữa các quy trình).

Tập tin IPC `klay.ipc` nằm ở thư mục `data` trên CN/PN.

Hãy thực hiện lệnh sau và kiểm tra kết quả.

Trong trường hợp CN,

```bash
$ ken attach /var/kend/data/klay.ipc
Chào mừng bạn đến với bảng điều khiển Klaytn JavaScript!

instance: Klaytn/vX.X.X/XXXX-XXXX/goX.X.X
 datadir: /var/kend/data
 modules: admin:1.0 debug:1.0 governance:1.0 istanbul:1.0 klay:1.0 miner:1.0 net:1.0 personal:1.0 rpc:1.0 txpool:1.0
 >
```

Trong trường hợp PN,

```bash
 $ kpn attach /var/kpnd/data/klay.ipc
 Chào mừng bạn đến với bảng điều khiển Klaytn JavaScript!

 instance: Klaytn/vX.X.X/XXXX-XXXX/goX.X.X
 coinbase: 0x67f68fdd9740fd7a1ac366294f05a3fd8df0ed40
 at block: 11573551 (Wed, 13 Feb 2019 07:12:52 UTC)
  datadir: /var/kpnd/data
  modules: admin:1.0 debug:1.0 istanbul:1.0 klay:1.0 miner:1.0 net:1.0 personal:1.0 rpc:1.0 txpool:1.0
  >
```

Bạn có thể kiểm tra các lệnh có thể sử dụng trên [Tài liệu API](https://github.com/klaytn/klaytn-docs-vn/blob/main/docs/installation-guide/dapp/json-rpc/README.md)

API hữu dụng để kiểm tra trạng thái của CN/PN:

* `klay.blockNumber` (để lấy số khối mới nhất)
* `net.peerCount` (để lấy số nút Klaytn được kết nối hiện tại)

### klay.blockNumber <a href="#klay-blocknumber" id="klay-blocknumber"></a>

Bạn có thể lấy số khối mới nhất để xem liệu các khối được tạo (đối với CN) hay được truyền (đối với CN và PN) đúng cách không dựa trên loại nút của bạn.

```javascript
> klay.blockNumber
11573819
```

### net.peerCount <a href="#net-peercount" id="net-peercount"></a>

```javascript
> net.peerCount
14
```

Dòng lệnh trên trả về một giá trị khác dựa trên loại nút.

* CN: số CN được kết nối + số PN được kết nối.
* PN: số CN được kết nối + số PN được kết nối + số EN được kết nối.


# Giám sát thiết lập

## Tổng quan <a href="#overview" id="overview"></a>

Đội ngũ Klaytn cung cấp một trang web để theo dõi CCN Klaytn tại <http://cypress.klaytn.net:3000>. Tác nhân giám sát `telegraf` được cài đặt trong mỗi CN/PN của CC để thu thập số liệu và gửi chúng đến máy chủ giám sát. Sau khi cài đặt, bạn có thể truy cập trang web giám sát để xem số liệu của CC Klaytn.

Quá trình cài đặt như sau:

1. Cài đặt `telegraf` trong CN/PN
2. Định cấu hình `telegraf`
3. Bắt đầu `telegraf`

## Cài đặt Telegraf <a href="#telegraf-installation" id="telegraf-installation"></a>

Hướng dẫn cài đặt Telegraf (Người dùng Amazon Linux 2, xem bên dưới): <https://docs.influxdata.com/telegraf/latest/introduction/installation/>

**Lưu ý cho Amazon Linux 2**

Để cài đặt Telegraph trên Amazon Linux 2, bạn có thể sử dụng kho lưu trữ yum của InfluxData như sau:

```
cat <<EOF | sudo tee /etc/yum.repos.d/influxdb.repo
[influxdb]
name = InfluxDB Repository - RHEL 7
baseurl = https://repos.influxdata.com/rhel/7/\$basearch/stable
enabled = 1
gpgcheck = 1
gpgkey = https://repos.influxdata.com/influxdb.key
EOF
```

## Thiết lập Telegraf <a href="#telegraf-setup" id="telegraf-setup"></a>

### Kích hoạt giám sát trong kcnd/kpnd <a href="#enable-monitoring-in-kcnd-kpnd" id="enable-monitoring-in-kcnd-kpnd"></a>

/etc/kcnd/conf/kcnd.conf

```
...
METRICS=1
PROMETHEUS=1
...
```

**Kiểm tra**

Bạn có thể xác nhận rằng hai tùy chọn trên đã được kích hoạt bằng cách kiểm tra xem cổng 61001 có đang mở hay không.

```
$ netstat -ntap | grep 61001
tcp        0      0 :::61001        :::*       LISTEN      8989/kcn
```

**Định cấu hình dịch vụ Telegraf**

Sao chép tập tin sau vào thư mục cấu hình `telegraf` (`/etc/telegraf/telegraf.d/`) và chỉnh sửa `nodetype`, `instance` và `hostname` cho phù hợp với từng nút:

```
[global_tags]
  # Change "cn" to "pn" for PN installation
  nodetype = "cn"

  # The CN/PN name (e.g. `example-cn`, `example-pn`)
  instance = "<hostname>"

[agent]
  # The CN/PN name (e.g. `example-cn`, `example-pn`)
  hostname = "<hostname>"

[[outputs.influxdb]]
  urls = [ "http://localhost:" ]
  database = "klaytn_cypress"

[[inputs.prometheus]]
  urls = [ "http://localhost:61001/metrics" ]
```

Thay đổi như sau trong `/etc/telegraf/telegraf.conf`:

* Loại bỏ phần `[[outputs.influxdb]]` bằng ghi chú

**Bắt đầu Telegraf**

```
$ systemctl restart telegraf
```

## Grafana <a href="#grafana" id="grafana"></a>

Nếu mỗi CN/PN có cấu hình và tác nhân ở trên, bạn có thể kiểm tra các thông số tại URL sau:

<http://cypress.klaytn.net:3000>

Là người vận hành CC, bạn có thể yêu cầu một tài khoản bằng cách cung cấp tên công ty và địa chỉ email của bạn trong kênh Slack. Xin lưu ý rằng chỉ các người vận hành CC mới được phép yêu cầu tài khoản Grafana.


# Thiết lập H/A

Định cấu hình CN để đạt được tính sẵn có cao là rất quan trọng trong việc vận hành hiệu quả Core Cell. Sơ đồ tính sẵn có cao được khuyến nghị tùy thuộc vào việc Core Cell được triển khai trên cơ sở hạ tầng vật lý hay trên đám mây.

## Hoạt động-chờ (khuyến nghị cho bare-metal) <a href="#active-standby-recommended-for-bare-metal" id="active-standby-recommended-for-bare-metal"></a>

Trong cấu hình này, hai nút CN được cài đặt cấu hình hoạt động-chờ. Trong quá trình hoạt động thông thường, nút hoạt động tham gia tạo khối, trong khi nút chờ chỉ đồng bộ hóa dữ liệu chuỗi từ mạng lưới. Cấu hình này đảm bảo rằng CN chờ có bản sao mới của dữ liệu chuỗi trong trường hợp nút hoạt động không thành công.

### Thiết lập <a href="#setup" id="setup"></a>

1. Tạo bản sao lưu của `khóa nút` của CN hoạt động.
2. Cài đặt CN chờ. Cấu hình này giống với CN hoạt động, ngoại trừ:
   * Nút chờ sử dụng `khóa nút` khác
   * Thêm địa chỉ của PN vào `$DATA_DIR/static-nodes.json`

### Dự phòng <a href="#failover" id="failover"></a>

1. Dừng CN chờ: `sudo systemctl stop kcnd`
2. Thay thế `khóa nút` của nút chờ bằng `khóa nút` của CN hoạt động không thành công.
3. Gán lại địa chỉ IP của CN hoạt động cho CN chờ.
4. Khởi chạy CN chờ và xác minh nó đã đồng bộ với mạng lưới: `sudo systemctl start kcnd`

## Bản sao lưu máy ảo & Thu thập dữ liệu (khuyến nghị cho đám mây) <a href="#machine-image-snapshot-recommended-for-cloud" id="machine-image-snapshot-recommended-for-cloud"></a>

Cơ sở hạ tầng đám mây cho phép người vận hành thay thế các nút không thành công nhanh chóng hơn mà không cần phải chạy CN chờ thứ 2. Thay vào đó, nó đảm bảo một CN mới có thể được cung cấp nhanh chóng và đi kèm bản sao cập nhật của dữ liệu chuỗi.

Thuật ngữ và quy trình chính xác có thể khác nhau giữa các môi trường đám mây khác nhau. Quy trình bên dưới dựa trên AWS (cụ thể là EC2 và EBS) nhưng có thể được điều chỉnh theo các nền tảng đám mây khác.

### Thiết lập <a href="#setup" id="setup"></a>

1. Tạo bản sao lưu của `khóa nút` của CN hoạt động.
2. Mỗi lần cấu hình và phần mềm CN được cập nhật, một bản sao lưu máy ảo sẽ được tạo ra (ví dụ: AMI). Đừng thêm khối lượng chứa `DATA_DIR` trong bản sao lưu này, nó sẽ được tách riêng ra.

### Dự phòng <a href="#failover" id="failover"></a>

Sử dụng bất kỳ nút PN của CC nào để thu thập dữ liệu chuỗi:

1. Kết nối với bất kỳ PN nào và dừng kpnd: `sudo systemctl stop kpnd`. Cần phải dừng kpnd trước để đảm bảo tính nhất quán của dữ liệu.
2. Sử dụng bảng điều khiển AWS, tạo bản thu thập dữ liệu của khối lượng chứa `DATA_DIR` của PN.
3. Bắt đầu kpnd: `sudo systemctl start kpnd`

Tạo một CN mới sử dụng bản sao CN hoặc dữ liệu chuỗi:

1. Tạo một phiên bản bằng bản sao CN (tạo trong phần "Thiết lập" phía trên).
2. Đính kèm khối lượng được tạo từ bản thu thập dữ liệu `$DATA_DIR` của PN.
3. Xóa tất cả các tập tin trong khối lượng ngoại trừ `$DATA_DIR/klay/chaindata`. Xác nhận rằng `DATA_DIR` trong `kcnd.conf` khớp với thư mục chứa dữ liệu chuỗi. Có thể sẽ cần đổi tên thư mục nếu tên khác nhau.
4. Sao chép `khóa nút` của CN không thành công vào `$DATA_DIR/klay/nodekey`.
5. Gán lại địa chỉ IP của CN không thành công vào nút thay thế.
6. Bắt đầu kcnd: `sudo systemctl start kcnd`
7. Xác minh CN đã đồng bộ với mạng lưới.

## Cân nhắc bổ sung <a href="#additional-considerations" id="additional-considerations"></a>

Gán lại IP công khai của CN không thành công cho CN thay thế sẽ giúp nút thay thế có thể kết nối ngay lập tức với các CN khác. Nếu IP thay đổi, CN mới sẽ không thể kết nối với mạng lưới cho đến khi tất cả các CCO khác cập nhật cấu hình tường lửa của mình.


# Chuỗi dịch vụ

## Đối tượng mục tiêu <a href="#intended-audience" id="intended-audience"></a>

* Nhà phát triển dApp cần TPS cao, phí giao dịch tối thiểu hoặc quyền riêng tư dữ liệu.
* Bất kỳ ai muốn xây dựng mạng lưới riêng tư cục bộ hoặc cơ sở dữ liệu sổ cái để thử nghiệm.

## Tổng quan về Chuỗi dịch vụ <a href="#service-chain-overview" id="service-chain-overview"></a>

Chuỗi dịch vụ Klaytn cung cấp các tính năng sau.

* Tính hoàn thiện tức thời.
* Chuyển token chuỗi chéo.
* Neo dữ liệu vào chuỗi chính.
* Hợp đồng cầu nối đa chữ ký để đáp ứng các yêu cầu bảo mật của doanh nghiệp.

![](/files/SGN1Xt14um6awlaoCIaw)

Đọc [Giải pháp mở rộng Klaytn](/content/klaytn/scaling-solutions) để biết thêm chi tiết về Chuỗi dịch vụ.


# Bắt đầu

Bằng cách làm theo các bước trong phần này, bạn sẽ nhanh chóng thiết lập và chạy mạng lưới ServiceChain, mạng lưới blockchain độc lập được kết nối với mạng thử nghiệm Klaytn.

Hướng dẫn này cung cấp hướng dẫn từng bước để thiết lập mạng lưới ServiceChain và kết nối mạng lưới đó với mạng lưới Baobab Klaytn. Bạn cũng sẽ biết cách kích hoạt neo định kỳ và chuyển giá trị chuỗi chéo. Để vận hành các dịch vụ blockchain thực tế với ServiceChain, chúng ta cần giải thích về Tính sẵn sàng cao, xây dựng ServiceChain theo bậc và chuyển giao giá trị giữa các ServiceChain kết nối.

* [Thiết lập chuỗi dịch vụ 4 nút](/content/installation-guide/deployment/service-chain/getting-started/4nodes-setup-guide)
* [Kết nối với Baobab](/content/installation-guide/deployment/service-chain/getting-started/en-scn-connection)
* [Chuyển giá trị chuỗi chéo](/content/installation-guide/deployment/service-chain/getting-started/value-transfer)
* [HA cho ServiceChain](/content/installation-guide/deployment/service-chain/getting-started/ha-for-sc)
* [Chuỗi dịch vụ lồng nhau](/content/installation-guide/deployment/service-chain/getting-started/nested-sc)
* [Chuyển giá trị giữa các chuỗi dịch vụ kết nối](/content/installation-guide/deployment/service-chain/getting-started/value-transfer-between-sibling)


# Thiết lập chuỗi dịch vụ 4 nút

Phần này trình bày cách thiết lập ServiceChain đa nút. Chúng ta sẽ thiết lập ServiceChain 4 nút đồng thuận với `chainID` 1002, như bạn có thể thấy trong hộp viền màu xanh trong hình bên dưới.

![](/files/DzENom6ErBTuACpc5W0t)

### Điều kiện tiên quyết <a href="#prerequisites" id="prerequisites"></a>

* Gói tải về nhị phân `kscn` và `homi` từ [Tải xuống](/content/installation-guide/deployment/download).
* 4 máy chủ Linux hoặc MacOS
* Yêu cầu phần cứng tối thiểu
  * CPU: 4 nhân (Intel Xeon hoặc tương đương), RAM: 16GB, HDD: 50GB
  * Vui lòng tham khảo [Yêu cầu hệ thống](/content/installation-guide/deployment/service-chain/references/system-requirements) để biết thêm chi tiết.

### Bước 0: Cài đặt SCN trên tất cả các nút <a href="#install-scn" id="install-scn"></a>

Quá trình cài đặt chính là giải nén gói đã tải xuống. Giải nén SCN trên mỗi máy chủ.

```console
$ tar xvf kscn-vX.X.X-XXXXX-amd64.tar.gz
x kscn-XXXXX-amd64/
x kscn-XXXXX-amd64/conf/
x kscn-XXXXX-amd64/conf/kscnd.conf
x kscn-XXXXX-amd64/bin/
x kscn-XXXXX-amd64/bin/kscnd
x kscn-XXXXX-amd64/bin/kscn
```

Để thuận tiện, chúng tôi sẽ thêm đường dẫn nhị phân vào $PATH. Sử dụng đường dẫn thực trên nút của bạn.

```console
$ export PATH=$PATH:~/path/to/kscn-XXXXX-amd64/bin
```

SCN cũng cung cấp nhiều trình phân bổ RPM như RHEL, CentOS và Fedora. Để biết thêm thông tin, vui lòng tham khảo [Cài đặt](/content/installation-guide/deployment/service-chain/references/scn/installation).

```console
$ curl -o /etc/yum.repos.d/klaytn.repo https://packages.klaytn.net/config/rhel/7/prod.repo
  % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed
     100 118 100 118 0 0 1113 0 --:--:-- --:--:-- --:--:-- 1102 

$ yum list | grep klaytn 
packages-klaytn-prod 31 kB/s | 2.9 kB 00:00 
homi.x86_64           v1.8.0-0.el7      packages-klaytn-prod 
kbnd.x86_64           v1.8.0-0.el7      packages-klaytn-prod 
kcnd.x86_64           v1.8.0-0.el7      packages-klaytn-prod 
kcnd-baobab.x86_64    v1.8.0-0.el7      packages-klaytn-prod 
kend.x86_64           v1.8.0-0.el7      packages-klaytn-prod 
kend-baobab.x86_64    v1.8.0-0.el7      packages-klaytn-prod 
kgen.x86_64           v1.8.0-0.el7      packages-klaytn-prod 
kpnd.x86_64           v1.8.0-0.el7      packages-klaytn-prod 
kpnd-baobab.x86_64    v1.8.0-0.el7      packages-klaytn-prod 
kscnd.x86_64          v1.8.0-0.el7      packages-klaytn-prod 
ksend.x86_64          v1.8.0-0.el7      packages-klaytn-prod 
kspnd.x86_64          v1.8.0-0.el7      packages-klaytn-prod 

$ yum install kscnd
```

### Bước 1: Tạo genesis.json và khóa nút <a href="#step-1-create-genesis-json-and-a-key" id="step-1-create-genesis-json-and-a-key"></a>

Chúng ta sẽ sử dụng tiện ích homi để tạo ra các tập tin cần thiết. `homi` là tiện ích tự động tạo tập lệnh, tập tin cấu hình và khóa riêng tư cần thiết để định cấu hình blockchain Klaytn. Bạn có thể thực thi homi từ bất kỳ máy bàn Linux/Mac nào.

Đầu tiên, giải nén tập tin homi mà bạn đã tải xuống.

```console
$ tar xvf homi-vX.X.X-XXXXX-amd64.tar.gz
x homi-XXXXX-amd64/
x homi-XXXXX-amd64/bin/
x homi-XXXXX-amd64/bin/homi
```

Chuyển đến thư mục `bin` và thực thi `homi` với các tùy chọn sau để tạo tập tin. `homi setup --gen-type local --cn-num 4 --test-num 1 --servicechain --chainID 1002 --p2p-port 22323 -o homi-output` Since Baobab's `chainID` is 1001, for convenience, the `chainID` of the ServiceChain constructed in this example is set to 1002. Khi vận hành một blockchain bằng cách khởi chạy một dịch vụ thực tế, bạn nên sử dụng dịch vụ đó sau khi đăng ký giá trị chainID mới tại <https://chainlist.defillama.com/> để chainID không trùng lặp với các ServiceChain khác. Cổng ServiceChain được đặt là 22323 hay chính là cổng mặc định.

```console
$ ./homi setup --gen-type local --cn-num 4 --test-num 1 --servicechain --chainID 1002 --p2p-port 22323 -o homi-output
Created :  homi-output/keys/passwd1
Created :  homi-output/keys/passwd2
Created :  homi-output/keys/passwd3
Created :  homi-output/keys/passwd4
Created :  homi-output/scripts/genesis.json
Created :  homi-output/keys/nodekey1
Created :  homi-output/keys/validator1
Created :  homi-output/keys/nodekey2
Created :  homi-output/keys/validator2
Created :  homi-output/keys/nodekey3
Created :  homi-output/keys/validator3
Created :  homi-output/keys/nodekey4
Created :  homi-output/keys/validator4
Created :  homi-output/scripts/static-nodes.json
Created :  homi-output/keys_test/testkey1
Created :  homi-output/keys_test/keystore1/0xdC7218621513f71d609653d22C39d79d558d9CDC
Created :  homi-output/Klaytn.json
Created :  homi-output/Klaytn_txpool.json
```

Trong số các đầu ra, chúng ta sẽ sử dụng `khóa nút*`, `genesis.json` và `static-nodes.json` trong các bước tiếp theo.

### Bước 2: Tùy chỉnh static-nodes.json <a href="#step-2-customize-static-nodes-json" id="step-2-customize-static-nodes-json"></a>

Mở `homi-output/scripts/static-nodes.json` trong trình soạn thảo văn bản, rồi cập nhật địa chỉ IP và cổng bằng giá trị thực của các nút của bạn. Trong ví dụ này, giả định rằng IP của mỗi nút SCN trong ServiceChain giống như trong hình bên dưới. Hãy nhớ cổng bạn đã gán ở đây vì nó sẽ được sử dụng sau trong bước 4.

![](/files/cnxkA13tMQx9IzbBWhKo)

```json
[
     "kni://38693ad4b17ff77...23153@192.168.0.1:22323?discport=0\u0026ntype=cn",
     "kni://f36d969b16f7337...1329b@192.168.0.2:22323?discport=0\u0026ntype=cn",
     "kni://16e55d8921ab034...b2bec@192.168.0.3:22323?discport=0\u0026ntype=cn",
     "kni://0973e792a421c1d...bbd71@192.168.0.4:22323?discport=0\u0026ntype=cn"
]
```

Sau khi bạn cập nhật `static-nodes.json`, hãy tải các thư mục đầu ra(`homi-output`) lên tất cả các SCN, tức là nút SCN-L2-01, SCN-L2-02, SCN-L2-03, SCN-L2-04 trong ví dụ này.

```console
$ scp -r path/to/homi-output/ user@192.168.0.1:~/
$ scp -r path/to/homi-output/ user@192.168.0.2:~/
$ scp -r path/to/homi-output/ user@192.168.0.3:~/
$ scp -r path/to/homi-output/ user@192.168.0.4:~/
```

### Bước 3: Khởi tạo nút <a href="#step-3-node-initialization" id="step-3-node-initialization"></a>

Bây giờ, chúng ta sẽ khởi tạo nút EN bằng tập tin khởi nguyên. Trên mỗi nút, hãy thực hiện lệnh sau. Điều này sẽ tạo thư mục dữ liệu lưu trữ dữ liệu chuỗi và bản ghi trên thư mục chủ của bạn. Bạn có thể thay đổi thư mục dữ liệu bằng lệnh dẫn hướng `--datadir`. Trong ví dụ này, chúng ta đặt thư mục dữ liệu thành `\~/data`.

```console
$ kscn --datadir ~/data init ~/homi-output/scripts/genesis.json

$ ls ~/data
keystore    klay        kscn
```

### Bước 4: Cài đặt `khóa nút` và `static-nodes.json` <a href="#step-4-install-nodekey" id="step-4-install-nodekey"></a>

Trên mỗi SCN, hãy sao chép `static-nodes.json` vào thư mục dữ liệu.

```console
$ cp ~/homi-output/scripts/static-nodes.json ~/data/
```

Ở bước 1, chúng ta đã tạo 4 khóa nút. Gán từng khóa nút cho SCN và sao chép `khóa nút` phù hợp vào từng thư mục dữ liệu của SCN. Ví dụ: sử dụng `nodekey1` cho nút SCN-L2-01(192.168.0.1) và sử dụng `nodekey2`, `nodekey3` và `nodekey4` tương ứng cho SCN-L2-02(192.168.0.2), SCN-L2-03(192.168.0.3) và SCN-L2-04(192.168.0.4).

```console
$ cp ~/homi-output/keys/nodekey{1..4} ~/data/klay/nodekey
```

![](/files/JHB9QitRrfSgOUUDum6S)

### Bước 5: Định cấu hình nút <a href="#step-5-configure-nodes" id="step-5-configure-nodes"></a>

Trên mỗi SCN, chuyển đến thư mục cài đặt kscn và chỉnh sửa `conf/kscnd.conf` như sau. `PORT` là cổng dùng để thiết lập `homi` và `SC_SUB_BRIDGE` cần thiết để kết nối cầu nối trong phần tiếp theo. Hiện tại, chỉ cần đặt nó thành 0. Trong `DATA_DIR`, nhập thư mục dữ liệu được sử dụng trrong bước 3.

```
...
PORT=22323
...
SC_SUB_BRIDGE=0
...
DATA_DIR=~/data
...
```

### Bước 6: Bắt đầu nút <a href="#step-6-start-nodes" id="step-6-start-nodes"></a>

Thực hiện lệnh sau trên tất cả các nút SCN.

```console
$ kscnd start
Starting kscnd: OK
```

Bạn có thể kiểm tra trạng thái tạo khối bằng cách xem `klay.blockNumber`. Nếu số này không phải là 0 thì nút đang hoạt động bình thường.

```console
$ kscn attach --datadir ~/data
> klay.blockNumber
10
```

Nếu bạn muốn dừng một nút, bạn có thể sử dụng lệnh `kscnd stop`

### (Ví dụ) Tạo và xác nhận giao dịch chuyển giá trị <a href="#example-creation-and-confirmation-of-a-value-transfer-transaction" id="example-creation-and-confirmation-of-a-value-transfer-transaction"></a>

Bây giờ, ServiceChain 4 nút đã hoạt động. Chúng ta sẽ thực hiện giao dịch chuyển giá trị trong ServiceChain để xác nhận cài đặt.

![](/files/1vbte3XH1spK0lpt9fwG)

#### Bước 1: Nhập tài khoản thử nghiệm <a href="#step-1-import-the-test-account" id="step-1-import-the-test-account"></a>

`testkey1` được tạo tự động bởi `homi` ở bước 1. KLAY được phân bổ cho tài khoản thử nghiệm như được mô tả trong `genesis.json` và được tạo bởi `homi`.

```console
$ kscn tài khoản import --datadir ~/data ~/homi-output/keys_test/testkey1
Tài khoản mới của bạn được khóa bằng mật khẩu. Vui lòng nhập mật khẩu. Đừng quên mật khẩu này.
Cụm mật khẩu:
Nhắc lại cụm mật khẩu:
Địa chỉ: {80119c31cdae67c42c8296929bb4f89b2a52cec4}
```

#### Bước 2: Mở khóa tài khoản <a href="#step-2-unlock-the-account" id="step-2-unlock-the-account"></a>

Chỉ có thể mở khóa tài khoản thông qua bảng điều khiển của nút SCN đã nhập `testkey1`.

```console
$ kscn attach --datadir ~/data
> personal.unlockAccount("80119c31cdae67c42c8296929bb4f89b2a52cec4")
Unlock tài khoản 80119c31cdae67c42c8296929bb4f89b2a52cec4
Passphrase:
true
```

#### Bước 3: Gửi giao dịch và kiểm tra số dư <a href="#step-3-send-a-transaction-and-check-the-balance" id="step-3-send-a-transaction-and-check-the-balance"></a>

```console
> klay.sendTransaction({from: "80119c31cdae67c42c8296929bb4f89b2a52cec4", to: "305c6cc464d5fe1e624679695a20d641a01688e1", value: 10})
"0xa0e7102e8f14200cec8d964aacc1c9ed7c22271078b2b213170c64333cbca8a3"
> klay.getBalance("305c6cc464d5fe1e624679695a20d641a01688e1")
10
```

{% hint style="info" %}
Hình thức đơn giản nhất của ServiceChain là có một SCN. ServiceChain được minh họa trong hướng dẫn này là ServiceChain 4 nút. Tuy nhiên, bạn có thể thiết lập ServiceChain một nút nếu muốn. Chỉ cần chuyển `--cn-num 1` thay vì `--cn-num 4` cho homi trong "Bước 1:Tạo genesis.json và khóa nút".

Cần ít nhất 4 nút để kháng lỗi byzantine. Do đó, số lượng SCN tối thiểu để đạt được tính sẵn sàng cao theo thuật toán BFT là 4. Có 2 nút SCN là không đủ, bởi vì nếu một SCN bị lỗi thì nút còn lại sẽ không thể đạt được sự đồng thuận.
{% endhint %}


# Kết nối với Baobab

Phần này trình bày cách kết nối mạng lưới ServiceChain 4 nút của bạn với mạng lưới Baobab. Bạn sẽ thiết lập EN Baobab và kết nối EN đó với một trong các SCN của bạn. Sau đó, bạn sẽ kích hoạt tính năng neo để đưa thông tin khối ServiceChain vào mạng lưới Baobab.

![](/files/s1v4V08xiGXnDQRnhgpq)

### Điều kiện tiên quyết <a href="#prerequisites" id="prerequisites"></a>

* 1 máy chủ Linux hoặc MacOS cho EN
* Yêu cầu phần cứng tối thiểu cho việc thử nghiệm
  * CPU: 4 nhân (Intel Xeon hoặc tương đương), RAM: 16GB, HDD: 50GB
  * Vui lòng tham khảo [Yêu cầu hệ thống](/content/installation-guide/deployment/service-chain/references/system-requirements) để biết thêm chi tiết.
* Tải xuống tập tin thực thi EN Baobab. Để biết danh sách đầy đủ các tập tin nhị phân có thể tải về, hãy xem [Tải xuống](/content/installation-guide/deployment/download).
* Giả định và hạn chế
  * Một mạng lưới ServiceChain đã được cài đặt và đang chạy. Vui lòng tham khảo [Thiết lập ServiceChain 4 nút](/content/installation-guide/deployment/service-chain/getting-started/4nodes-setup-guide) để thiết lập mạng lưới.
  * Một EN Baobab.
  * Một EN chỉ có thể kết nối với một SCN vì hệ thống chỉ hỗ trợ kết nối một-một.
  * Mọi SCN không cần phải kết nối với EN.

### Bước 0: Cài đặt EN Baobab <a href="#install-baobab-en" id="install-baobab-en"></a>

Quá trình cài đặt chính là giải nén gói đã tải xuống. Giải nén tập tin lưu trữ trên mỗi máy chủ EN.

```bash
EN-01$ tar xvf ken-baobab-vX.X.X-XXXXX-amd64.tar.gz
```

### Bước 1: Chuẩn bị genesis.json <a href="#step-1-preparing-genesis-json" id="step-1-preparing-genesis-json"></a>

Từ máy chủ EN, tải về `genesis.json` cho mạng lưới `Baobab`.

```
EN-01$ curl -X GET https://packages.klaytn.net/baobab/genesis.json -o ~/genesis.json
```

### Bước 2: Khởi tạo nút EN <a href="#step-2-en-node-initialization" id="step-2-en-node-initialization"></a>

Bây giờ, chúng ta sẽ khởi tạo nút EN bằng tệp khởi nguyên. Thực thi các lệnh sau. Điều này sẽ tạo thư mục dữ liệu lưu trữ dữ liệu chuỗi và bản ghi trên thư mục chủ của bạn. Bạn có thể thay đổi thư mục dữ liệu bằng lệnh dẫn hướng `--datadir`.

```
EN-01$ ken init --datadir ~/data ~/genesis.json
```

### Bước 3: Định cấu hình nút EN <a href="#step-3-configure-the-en-node" id="step-3-configure-the-en-node"></a>

Chuyển đến thư mục cài đặt ken và đổi tên `mv kend_baobab.conf kend.conf`, rồi chỉnh sửa `conf/kend.conf` như sau.

```
...
NETWORK="baobab"
...
SC_MAIN_BRIDGE=1
...
DATA_DIR=~/data
...
```

### Bước 4: Bắt đầu nút EN <a href="#step-4-start-the-en-node" id="step-4-start-the-en-node"></a>

```
EN-01$ kend start
Starting kscnd: OK
```

Bạn có thể kiểm tra trạng thái đồng bộ bằng cách xem `klay.blockNumber`. Nếu số này không phải là 0 thì nút đang hoạt động bình thường. Việc tải về tất cả các khối trên mạng lưới Baobab có thể mất nhiều thời gian tùy thuộc vào điều kiện mạng lưới và hiệu suất phần cứng, vì vậy chúng tôi khuyên bạn nên sử dụng [Đồng bộ nhanh](/content/installation-guide/deployment/endpoint-node/installation-guide/configuration) để đồng bộ hóa các khối.

```
EN-01$ ken attach --datadir ~/data
> klay.blockNumber
21073
```

Nếu bạn muốn dừng một nút, bạn có thể sử dụng lệnh `kend stop`

### Bước 5: Kiểm tra KNI của nút EN <a href="#step-5-check-kni-of-en-node" id="step-5-check-kni-of-en-node"></a>

Lưu ý KNI của EN-01 là thông tin được sử dụng để kết nối từ nút SCN-L2-01. Giá trị này sẽ được sử dụng trong bước tiếp theo khi tạo `main-bridges.json`.

```
EN-01$ ken attach --datadir ~/data
> mainbridge.nodeInfo.kni
"kni://0f7aa6499553...25bae@[::]:50505?discport=0"
```

![](/files/QMecy6LTTllRsyl1RYbH)

### Bước 6: Tạo main-bridges.json <a href="#step-6-create-main-bridges-json" id="step-6-create-main-bridges-json"></a>

Đăng nhập vào SCN-L2-01 (lưu ý: không phải nút EN-01) và tạo `main-bridges.json` trên `~/data`. Thay thế `[::]` nằm sau chữ cái `@` bằng địa chỉ IP của nút EN-01.

```
SCN-L2-01$ echo '["kni://0f7aa6499553...25bae@192.168.1.1:50505?discport=0"]' > ~/data/main-bridges.json
```

### Bước 7: Định cấu hình SCN rồi Khởi động lại kscn <a href="#step-7-configure-scn-then-restart-kscn" id="step-7-configure-scn-then-restart-kscn"></a>

Từ tập lệnh shell của nút SCN-L2-01, hãy chỉnh sửa `kscn-XXXXX-amd64/conf/kscnd.conf`. Nếu `SC_SUB_BRIDGE` được đặt thành 1, quá trình neo dữ liệu sẽ tự động bắt đầu khi nút SCN-L2-01 bắt đầu. Trong ví dụ này, `SC_PARENT_CHAIN_ID` được đặt thành 1001 vì `chainID` của chuỗi gốc, Baobab, là 1001. `SC_ANCHORING_PERIOD` là tham số quyết định khoảng thời gian gửi giao dịch neo đến chuỗi chính. Bằng cách đặt giá trị thành 10, bạn đã định cấu hình nút để thực hiện việc neo sau mỗi 10 khối. Giá trị mặc định là 1.

```
...
SC_SUB_BRIDGE=1
...
SC_PARENT_CHAIN_ID=1001
...
SC_ANCHORING_PERIOD=10
...
```

Khởi động lại kscn bằng cách thực hiện lệnh sau:

```
SCN-L2-01$ kscnd stop
Shutting down kscnd: Killed
SCN-L2-01$ kscnd start
Starting kscnd: OK
```

Kiểm tra xem SCN-L2-01 có được kết nối với EN-01 hay không bằng cách kiểm tra `subbridge.peers.length`

```
SCN-L2-01$ kscn attach --datadir ~/data
> subbridge.peers.length
1
```

### Neo <a href="#anchoring" id="anchoring"></a>

Sau khi kết thúc kết nối EN-01 và SCN-L2-01, bạn có thể ghi lại thông tin khối ServiceChain trên chuỗi mẹ thông qua Neo. Trong phần này, bạn sẽ nạp tiền vào tài khoản người vận hành mẹ, bật Neo và kiểm tra số khối được neo.

#### Bước 1: Lấy KLAY để thử neo <a href="#step-1-get-klay-to-test-anchoring" id="step-1-get-klay-to-test-anchoring"></a>

Việc neo yêu cầu SCN-L2-01 thực hiện giao dịch neo với Baobab. Vì vậy, tài khoản `subbridge.parentOperator` phải có đủ KLAY để thanh toán phí giao dịch. Lấy KLAY từ [Vòi Ví Baobab ](https://baobab.wallet.klaytn.foundation/)và chuyển một số KLAY cho `parentOperator`. Để neo dữ liệu vào dịch vụ thực, `parentOperator` cần có đủ KLAY để thanh toán phí giao dịch.

```
SCN-L2-01$ kscn attach --datadir ~/data
> subbridge.parentOperator
"0x3ce216beeafc62d20547376396e89528e1d778ca"
```

![](/files/vIN9lTYZss0pfPRT8Ed2)

#### Bước 2: Bắt đầu neo <a href="#step-2-start-anchoring" id="step-2-start-anchoring"></a>

Để bắt đầu neo, hãy thực hiện lệnh sau:

```
SCN-L2-01$ kscn attach --datadir ~/data
> subbridge.anchoring(true)
true
```

Sau khi bắt đầu neo, bạn có thể kiểm tra khối mới nhất được neo vào Baobab bằng cách sử dụng `subbridge.latestAnchoredBlockNumber`. Xin lưu ý rằng chỉ có thể làm điều này sau khi EN đã gắn với khối Baobab mới nhất. Theo mặc định, SCN-L2-01 sẽ thử neo trên mọi khối từ khối mà tính năng neo được bật. Có thể đặt khoảng thời gian neo bằng cách thay đổi `SC_ANCHORING_PERIOD`. Nếu giá trị được đặt thành 10, nút sẽ thử neo khi số khối là bội số của 10.

```
SCN-L2-01$ kscn attach --datadir ~/data
> subbridge.latestAnchoredBlockNumber
100
```

![](/files/9tSt5Oamndb1th6avKEt)


# Chuyển giá trị chuỗi chéo

Phần này sẽ giải thích cách bật tính năng chuyển giá trị ERC-20 giữa mạng lưới Baobab và ServiceChain của bạn bằng mã thử nghiệm được cung cấp. Bạn sẽ thêm KLAY vào tài khoản người vận hành và triển khai các hợp đồng cầu nối và ERC-20. Sau đó, bạn sẽ đăng ký địa chỉ hợp đồng trên SCN. Bạn sẽ thử chuyển giá trị ERC-20.

### Điều kiện tiên quyết <a href="#prerequisites" id="prerequisites"></a>

* Giả định rằng bạn đã cài đặt ServiceChain và kết nối ServiceChain với EN Baobab theo hướng dẫn trong [Kết nối với Baobab](/content/installation-guide/deployment/service-chain/getting-started/en-scn-connection).
* Sao chép kho lưu trữ [servicechain-value-transfer-examples](https://github.com/klaytn/servicechain-value-transfer-examples).
* Cài đặt `Node.js` (v14) và `npm` ([Cách cài đặt](https://nodejs.org/en/download/package-manager/))
  * Ví dụ này sử dụng hai gói, axios và caver-js. Cả hai gói này đều hỗ trợ v14.

### Chuyển token ERC-20 (một bước) <a href="#erc-20-token-transfer-onestep" id="erc-20-token-transfer-onestep"></a>

#### Bước 1: Thêm KLAY vào tài khoản người vận hành. <a href="#step-1-add-klay-to-the-operator-accounts" id="step-1-add-klay-to-the-operator-accounts"></a>

Kết nối với SCN và kiểm tra địa chỉ tài khoản bằng cách thực thi `subbridge.parentOperator` và `subbridge.childOperator`.

```
$ kscn attach --datadir ~/data
> subbridge.childOperator
"0x10221f7f9355017cd0c11444e7eecb99621bacce"
> subbridge.parentOperator
"0x3ce216beeafc62d20547376396e89528e1d778ca"
```

![](/files/3cVtO5cMZa5vNs8T912D)

`subbridge.parentOperator` và `subbridge.childOperator` phải có đủ KLAY để gửi giao dịch. Lưu ý rằng `subbridge.parentOperator` là tài khoản trên mạng lưới Baobab và `subbridge.childOperator` là tài khoản trên mạng lưới ServiceChain. Tạo tài khoản thử nghiệm trên [Ví Baobab](https://baobab.wallet.klaytn.foundation/) và lấy KLAY để thử từ vòi. Sau đó, gửi một số KLAY đến `parentOperator`. `childOperator` phải lấy KLAY từ tài khoản thử nghiệm do `homi` tạo ([Tham khảo Hướng dẫn thiết lập EN và kết nối SCN](/content/installation-guide/deployment/service-chain/getting-started/en-scn-connection)).

```
$ kscn tài khoản import ~/homi-output/keys_test/testkey1
Tài khoản mới của bạn được khóa bằng mật khẩu. Vui lòng nhập mật khẩu. Đừng quên mật khẩu này.
Cụm mật khẩu:
Nhắc lại cụm mật khẩu:
Địa chỉ: {80119c31cdae67c42c8296929bb4f89b2a52cec4}
```

```
$ kscn attach --datadir ~/data
> personal.unlockAccount("80119c31cdae67c42c8296929bb4f89b2a52cec4")
Unlock tài khoản 80119c31cdae67c42c8296929bb4f89b2a52cec4
Passphrase:
True
> klay.sendTransaction({from:"80119c31cdae67c42c8296929bb4f89b2a52cec4", to:subbridge.childOperator, value: web3.toPeb(1000, "KLAY")})
"0x84caab84ebf0c4bb4ecf0a7849f1de3e479f1863a95f70c51047a7ca7bc64b33"
```

Kiểm tra xem các tài khoản của người vận hành có đủ số dư không. Bạn có thể truy vấn từ bảng điều khiển của nút SCN nơi cài đặt cầu nối con như sau:

```
> klay.getBalance(subbridge.childOperator)
1e+21
> subbridge.childOperatorBalance
1e+21
> subbridge.parentOperatorBalance
1e+18
```

#### Bước 2: Triển khai hợp đồng <a href="#step-2-deploy-contracts" id="step-2-deploy-contracts"></a>

* Kết nối với SCN và chuẩn bị môi trường nút để triển khai hợp đồng. Sao chép kho lưu trữ [servicechain-value-transfer-examples](https://github.com/klaytn/servicechain-value-transfer-examples).

![](/files/g0d98SVbFQyIdBvgSurL)

Trong bước này, chúng ta sẽ triển khai cả hợp đồng cầu nối và hợp đồng token trong chuỗi mẹ cũng như chuỗi con. Hợp đồng token dành cho việc thử nghiệm tạo/chuyển và hợp đồng cầu nối được sử dụng để lắng nghe/xử lý các yêu cầu chuyển giá trị.

```bash
$ git clone https://github.com/klaytn/servicechain-value-transfer-examples
$ cd servicechain-value-transfer-examples
$ npm install
$ cd erc20
```

Trên trình chỉnh sửa văn bản, hãy chỉnh sửa `bridge_info.json` như bên dưới.

* Thay thế `url` trong phần `child` (nút SCN trên mạng lưới ServiceChain) bằng IP nút SCN của bạn và số cổng thích hợp từ `RPC_PORT` trong `kscnd.conf`.
* Thay thế `child.key` bằng `testkey1` được tạo bởi `homi`.
* Đặt `child.operator` thành địa chỉ `subbridge.childOperator` đã kiểm tra ở bước trước.
* Thay thế `url` trong phần `parent` (nút EN trên mạng lưới Baobab) bằng IP nút EN của bạn và số cổng thích hợp từ `RPC_PORT` trong `kend.conf`.
* Thay thế `parent.key` bằng khóa riêng tư của tài khoản thử nghiệm được tạo từ [Ví Baobab](https://baobab.wallet.klaytn.foundation/) ở bước trước.
* Đặt `parent.operator` làm `subbridge.parentOperator` trong bước trước đó.

```
{
     "child" : {
         "url": "http://192.168.0.1:7551",
         "key": "0x66cb283353589a10866b58d388e9d956e5a9c873a8c78fa4411d460c19c494ea",
         "operator": "0x10221f7f9355017cd0c11444e7eecb99621bacce"
     },
     "parent" : {
         "url": "http://192.168.0.5:8551",
         "key": "0x26f4b5ac42ceabcfd3b23a991fdbfc792d10ce700a99582fdf9185a8f163b790",
         "operator": "0x3ce216beeafc62d20547376396e89528e1d778ca"
     }
 }
```

Thực hiện triển khai token bằng cách chạy lệnh `node erc20-deploy.js`. Tập lệnh này triển khai cả hợp đồng cầu nối và hợp đồng token, đồng thời xuất ra sử dụng API để khởi tạo cặp cầu nối.

```
$ node erc20-deploy.js
------------------------- erc20-deploy START -------------------------
> info.bridge: 0xEa024d8101E112330f2d7B1a7e7932034E206721
> info.token: 0xbE641028610F628835C36F12bE62d54d74308D70
> info.bridge: 0xA5af6Ffe13b367626B5AdF827DdE7438E3Db4463
> info.token: 0x52F8Fa79Fa6D37b18b7AC8f9Ca835373f3C9270f
> subbridge.registerBridge("0xEa024d8101E112330f2d7B1a7e7932034E206721", "0xA5af6Ffe13b367626B5AdF827DdE7438E3Db4463")
> subbridge.subscribeBridge("0xEa024d8101E112330f2d7B1a7e7932034E206721", "0xA5af6Ffe13b367626B5AdF827DdE7438E3Db4463")
> subbridge.registerToken("0xEa024d8101E112330f2d7B1a7e7932034E206721", "0xA5af6Ffe13b367626B5AdF827DdE7438E3Db4463", "0xbE641028610F628835C36F12bE62d54d74308D70", "0x52F8Fa79Fa6D37b18b7AC8f9Ca835373f3C9270f")
------------------------- erc20-deploy END -------------------------
```

#### Bước 3: Chuyển token <a href="#step-3-token-transfer" id="step-3-token-transfer"></a>

![](/files/mrfD0cyUIP0ytaDAMfnW)

Thực hiện chuyển token bằng lệnh `node erc20-transfer-1step.js`. Quá trình chuyển token một bước này yêu cầu sửa đổi việc triển khai token ERC-20. Nếu bạn không muốn sửa đổi hợp đồng token hoặc bạn đã triển khai hợp đồng token khác, vui lòng tham khảo [Chuyển token ERC-20 (hai bước)](#erc-20-token-transfer-twostep).

```
$ node erc20-transfer-1step.js
------------------------- erc20-transfer-1step START -------------------------
alice balance: 0
requestValueTransfer..
alice balance: 100
------------------------- erc20-transfer-1step END -------------------------
```

Nếu kết quả là `alice balance: 100` thì việc chuyển token đã được thực thi thành công.

### Chuyển token ERC-20 (hai bước) <a href="#erc-20-token-transfer-twostep" id="erc-20-token-transfer-twostep"></a>

Chạy erc20-transfer-2step.js để xem ví dụ về chuyển hai bước. Với ví dụ chuyển token hai bước này, có thể sử dụng hợp đồng token ERC-20 chưa sửa đổi. Quá trình chuyển hai bước bao gồm hai lệnh gọi hàm: (1) trước tiên hãy phê duyệt hợp đồng cầu nối, rồi (2) gọi hàm hợp đồng `requestERC20Transfer()`. Chúng ta không triển khai hợp đồng trong phần này vì đã triển khai cả hợp đồng cầu nối và hợp đồng token. Bạn phải triển khai trước nếu bạn chưa triển khai chúng. Bạn có thể triển khai hợp đồng bằng cách sử dụng `node erc20-deploy.js`.

```
$ node erc20-transfer-2step.js
> ------------------------- erc20-transfer-2step START -------------------------
> alice balance: 100
> requestValueTransfer..
> alice balance: 200
------------------------- erc20-transfer-2step END -------------------------
```

### Chuyển token KIP-7 qua giao diện ERC-20 (hai bước) <a href="#kip-7-token-transfer-via-erc-20-interface-two-step" id="kip-7-token-transfer-via-erc-20-interface-two-step"></a>

[KIP-7](https://kips.klaytn.foundation/KIPs/kip-7) là tiêu chuẩn token tương thích với ERC-20. Chúng ta có thể gọi hàm `requestERC20Transfer()` cho hợp đồng token KIP-7 để chuyển token KIP-7 giữa chuỗi mẹ và chuỗi con. Trong trường hợp gửi token KIP-7 qua giao diện ERC-20, chúng ta gọi hàm `approve()` để cho phép cầu nối gửi token thay mặt cho người gửi giao dịch. Sau đó, gọi hàm `requestERC20Transfer()`. Lệnh dưới đây triển khai hợp đồng cầu nối và hợp đồng KIP-7.

```
$ node kip7-deploy.js
> ------------------------- kip7-deploy START -------------------------
> info.bridge: 0x04e929Cd2A08acd28a210369407D8Ca237Edd8FE
> info.token: 0xE0E2fC6C7d1eB069153E0c12a4C87B01586b39e7
> info.bridge: 0xEb502159A4B4E876B1cb423f250DCC0d276e01b6
> info.token: 0xd4f02Ca1d49674056A9ec78fbBDc9e1e97726A4F
> subbridge.registerBridge("0x04e929Cd2A08acd28a210369407D8Ca237Edd8FE", "0xEb502159A4B4E876B1cb423f250DCC0d276e01b6")
> subbridge.subscribeBridge("0x04e929Cd2A08acd28a210369407D8Ca237Edd8FE", "0xEb502159A4B4E876B1cb423f250DCC0d276e01b6")
> subbridge.registerToken("0x04e929Cd2A08acd28a210369407D8Ca237Edd8FE", "0xEb502159A4B4E876B1cb423f250DCC0d276e01b6", "0xE0E2fC6C7d1eB069153E0c12a4C87B01586b39e7", "0xd4f02Ca1d49674056A9ec78fbBDc9e1e97726A4F")
------------------------- kip7-deploy END -------------------------
```

Lệnh dưới đây là một ví dụ về việc gửi token KIP-7 bằng giao diện ERC-20 với `requestERC20Transfer()`.

```
$ node kip7-transfer-2step-erc20-interface.js
> ------------------------- kip7-transfer-2step-erc20-interface START -------------------------
> alice balance: 0
> requestValueTransfer..
> alice balance: 100
> ------------------------- kip7-transfer-2step-erc20-interface END -------------------------
```

Vui lòng tham khảo [service-chain-value-transfer-example](https://github.com/klaytn/servicechain-value-transfer-examples) cho các trường hợp khác.

### Hỗ trợ riêng cho KIP-7 và KIP-17 (Sẽ được triển khai) <a href="#native-support-for-kip-7-and-kip-17-to-be-implemented" id="native-support-for-kip-7-and-kip-17-to-be-implemented"></a>

Hiện tại, hợp đồng cầu nối do đội ngũ Klaytn cung cấp chỉ hỗ trợ `requestERC20Transfer()` và `requestERC721Transfer()` để chuyển token. Các chức năng yêu cầu tương ứng cho KIP-7 và KIP-17 sẽ sớm được hỗ trợ. Trước khi hoàn tất triển khai, như bạn có thể thấy ở trên, bạn có thể chuyển token KIP-7 bằng giao diện ERC-20.

### Chuyển giá trị cho ERC-721, KIP-17 và KLAY <a href="#value-transfer-for-erc721-kip17-and-klay" id="value-transfer-for-erc721-kip17-and-klay"></a>

Quy trình làm việc cho ERC-721, KIP-17 và KLAY giống như ở trên. Các thư mục [`erc721`](https://github.com/klaytn/servicechain-value-transfer-examples/tree/main/erc721), [`kip17`](https://github.com/klaytn/servicechain-value-transfer-examples/tree/main/kip17) và [`klay`](https://github.com/klaytn/servicechain-value-transfer-examples/tree/main/klay) chứa mã nguồn tương tự trong ví dụ.


# HA (Tính sẵn sàng cao) dành cho Chuỗi dịch vụ

Nếu chỉ có một cầu nối được sử dụng trong ServiceChain thì cầu nối đó có thể trở thành một điểm lỗi duy nhất. Để giải quyết vấn đề này, chúng tôi sẽ mô tả cách bạn có thể xây dựng hệ thống HA với hai hoặc nhiều cầu nối. Như minh họa trong hình bên dưới, hãy định cấu hình các cầu nối được kết nối thành ít nhất hai cặp để ngay cả khi có sự cố trong một kết nối cầu nối, việc neo dữ liệu và chuyển giá trị giữa các chuỗi vẫn có thể hoạt động bình thường qua cầu nối còn lại.

![](/files/ekuKtP5L6MNdw4gGPZTC)

### Điều kiện tiên quyết <a href="#prerequisites" id="prerequisites"></a>

* Cầu nối chính của EN và cầu nối con của SCN phải được kết nối. Nếu chúng không được kết nối, vui lòng tham khảo [Kết nối Baobab](/content/installation-guide/deployment/service-chain/getting-started/en-scn-connection) để thiết lập kết nối.
* Phần này mô tả cách thêm một cầu nối bổ sung giữa Baobab và ServiceChain. Tương tự, bạn cũng có thể thiết lập HA bằng cách thêm một cầu nối khác.

### Bước 1: Thêm một cầu nối khác giữa EN-SCN <a href="#step-1-adding-another-bridge-between-en-scn" id="step-1-adding-another-bridge-between-en-scn"></a>

Trong [Kết nối với Baobab](/content/installation-guide/deployment/service-chain/getting-started/en-scn-connection), chúng ta giả sử rằng EN và SCN được kết nối bằng cầu nối tương ứng là EN-01 và SCN-L2-01. Trong phần này, chúng ta sẽ thêm một cầu nối khác giữa EN-02 và SCN-L2-02. Vì quy trình giống nhau nên ta sẽ chỉ giải thích ngắn gọn.

![](/files/PcnVvQd43uE3DihMWRMz)

Sau khi xây dựng EN-02, hãy đặt `SC_MAIN_BRIDGE` thành 1 trong `conf/kend.conf` và khởi động lại ken trên EN-02.

```console
SC_MAIN_BRIDGE=1
```

Kiểm tra thông tin KNI của EN-02 bằng lệnh sau:

```console
EN-02$ ken attach --datadir ~/data
> mainbridge.nodeInfo.kni
"kni://eb8f21df10c6562...25bae@[::]:50505?discport=0"
```

Đăng nhập vào SCN-L2-02 và tạo `main-bridges.json` bằng KNI của EN-02. Vui lòng đảm bảo rằng nó phải ở định dạng mảng JSON với dấu ngoặc vuông.

```console
SCN-L2-02$ echo '["kni://eb8f21df10c6562...25bae@192.168.0.5:50505?discport=0"]' > ~/data/main-bridges.json
```

Trên tập lệnh shell của SCN-L2-02, chỉnh sửa `kscn-XXXXX-amd64/conf/kscnd.conf` như bên dưới. Để kết nối cầu nối, hãy đặt `SC_SUB_BRIDGE` thành 1. `SC_PARENT_CHAIN_ID` được đặt thành `chainID` 1001 của Baobob. `SC_ANCHORING_PERIOD` là tham số quyết định khoảng thời gian gửi giao dịch neo đến chuỗi mẹ. Trong ví dụ này, một giao dịch neo được gửi đến chuỗi mẹ (Baobab) sau mỗi 10 khối con.

```
...
SC_SUB_BRIDGE=1
...
SC_PARENT_CHAIN_ID=1001
...
SC_ANCHORING_PERIOD=10
...
```

Nếu bạn khởi động lại ken trên EN-02, một cầu nối sẽ được kết nối tự động giữa EN-02 và SCN-L2-02 và quá trình neo dữ liệu sẽ bắt đầu từ điểm kết nối được tạo như minh họa trong hình bên dưới.

Sau khi thêm cầu nối giữa EN-02 và SCN-L2-02, bạn có thể thấy kết nối giữa các nút được thiết lập như minh họa bên dưới.

![](/files/eMlPQg5KOt8smStgkT2Z)

### Bước 2: Đăng ký và đặt mua Hợp đồng cầu nối <a href="#step-2-registering-and-subscribing-the-bridge-contract" id="step-2-registering-and-subscribing-the-bridge-contract"></a>

Như minh họa trong hình trên, hợp đồng cầu nối chỉ được đăng ký trong EN-01 và SCN-L2-01.

Kết nối với bảng điều khiển SCN-L2-02 và chạy các API để đăng ký cầu nối, đặt mua cầu nối và đăng ký token. Hợp đồng cầu nối và token được tạo trong khi triển khai hợp đồng cầu nối với EN-01 và SCN-L2-01 ở bước 2 của [Chuyển giá trị chuỗi chéo](/content/installation-guide/deployment/service-chain/getting-started/value-transfer).

```
$ kscn attach --datadir ~/data
> subbridge.registerBridge("0xCHILD_BRIDGE_ADDR", "0xPARENT_BRIDGE_ADDR")
null
> subbridge.subscribeBridge("0xCHILD_BRIDGE_ADDR", "0xPARENT_BRIDGE_ADDR")
null
> subbridge.registerToken("0xCHILD_BRIDGE_ADDR", "0xPARENT_BRIDGE_ADDR", "0xCHILD_TOKEN_ADDR", "0XPARENT_TOKEN_ADDR")
null
```

![](/files/alfjlReRdoS4r6bYzQen)

Trong hợp đồng cầu nối, cần cập nhật thông tin về việc thêm một cầu nối bổ sung. Ghi thông tin người vận hành con và người vận hành mẹ của cầu nối bổ sung được thêm vào trong tập tin `erc20/erc20-addOperator4HA.js` của [service-chain-value-transfer-example](https://github.com/klaytn/servicechain-value-transfer-examples) và thực thi `node erc20-addOperator4HA.js`.

```
// register operator
await conf.child.newInstanceBridge.methods.registerOperator("0xCHILD_BRIDGE_ADDR").send({ from: conf.child.sender, gas: 100000000, value: 0 });
await conf.parent.newInstanceBridge.methods.registerOperator("0xPARENT_BRIDGE_ADDR").send({ from: conf.parent.sender, gas: 100000000, value: 0 });
```

Khi có nhiều cầu nối, việc chuyển giá trị có thể được thực hiện an toàn hơn bằng cách đặt một ngưỡng. Chỉ có thể kích hoạt chuyển giá trị khi một người vận hành trên ngưỡng yêu cầu chuyển giá trị như bình thường. Ví dụ: như trong ví dụ hiện tại, nếu có hai cặp cầu nối và ngưỡng được đặt thành 2, chỉ có thể thực hiện việc chuyển giá trị khi cả hai được yêu cầu như bình thường. Nghĩa là, ngay cả khi một cầu nối bị tấn công và gửi một yêu cầu bất thường, điều này vẫn có thể được ngăn chặn. Giá trị mặc định của ngưỡng là 1. Trong tập tin `erc20/erc20-addOperator4HA.js` của [service-chain-value-transfer-example](https://github.com/klaytn/servicechain-value-transfer-examples), hãy bỏ ghi chú mã bên dưới và đặt giá trị ngưỡng rồi chạy mã đó để thay đổi ngưỡng cho hợp đồng cầu nối.

```
// // set threshold
// await conf.child.newInstanceBridge.methods.setOperatorThreshold(0, "your threshold number").send({ from: conf.child.sender, gas: 100000000, value: 0 });
// await conf.parent.newInstanceBridge.methods.setOperatorThreshold(0, "your threshold number").send({ from: conf.parent.sender, gas: 100000000, value: 0 });
```

Khi quá trình đăng ký hoàn tất, hợp đồng cầu nối được đăng ký trong cả EN-02 và SCN-L2-02 như minh họa trong hình bên dưới để định cấu hình HA.

![](/files/jOL8IurYFrCeWNJuqB1P)

Khi hai hoặc nhiều cặp cầu nối được kết nối cho HA, các giao dịch neo dữ liệu cho cùng một khối có thể xảy ra nhiều lần và các giao dịch chuyển giá trị cũng có thể xảy ra nhiều lần. Bởi vậy cần trả phí bổ sung.


# Chuỗi dịch vụ lồng nhau

Chương này giải thích cách xây dựng mạng lưới ServiceChain theo cấu trúc phân cấp bằng cách thêm mạng lưới ServiceChain mới vào mạng lưới ServiceChain đã được xây dựng trong chương trước. Trong ví dụ này, mạng lưới ServiceChain được thêm vào cũng bao gồm 4 SCN. Mạng lưới ServiceChain được xây dựng trong chương trước là L2 còn Mạng lưới ServiceChain mới được xây dựng sẽ là L3. Chúng ta sẽ kết nối một cầu nối giữa L2 và L3 để tạo ra một cấu trúc phân cấp. Cấu trúc tổng thể của mạng lưới ServiceChain được xây dựng trong chương này sẽ như trong hình bên dưới.

![](/files/OdElUckAWCjsF8b50KUs)

### Điều kiện tiên quyết <a href="#prerequisites" id="prerequisites"></a>

* Giả sử rằng bạn đã chuyển sang cấu hình ServiceChain và EN Baobab được mô tả trong [Chuỗi dịch vụ lồng nhau](/content/installation-guide/deployment/service-chain/getting-started/nested-sc). Vì vậy, chúng ta sẽ giải thích ngắn gọn những gì đã được giải thích trong phần trước.
* Giả định và hạn chế
  * Một EN có thể kết nối trực tiếp với một trong các SCN của ServiceChain L2. Tương tự, một SCN trong L2 của ServiceChain có thể kết nối một-một với một trong các SCN trong L3.
  * Một nút SCN có thể có một cầu chính và cả một cầu nối con. Tuy nhiên, số cổng của cầu nối chính và cầu nối con phải được đặt khác nhau. (Ví dụ: cầu nối chính: 50505, cầu nối con: 50506)
  * Không phải tất cả các SCN trong L2 đều cần có cầu nối đến EN và tương tự như vậy, không phải tất cả các SCN trong L3 đều cần cầu nối đến L2. Tuy nhiên, để đạt được tính sẵn sàng cao, nên có hai hoặc nhiều cặp cầu nối chính và cầu nối con giữa các chuỗi. Trong chương này, chỉ một cặp sẽ được kết nối giữa L2 và L3 và tính sẵn sàng cao giữa L2 và L3 cũng giống như HA giữa Baobab và L2.

### Bước 1: Tạo và cập nhật dữ liệu Homi cho L3 <a href="#step-1-create-and-update-homi" id="step-1-create-and-update-homi"></a>

Giống như khi định cấu hình ServiceChain L2, hãy thực thi lệnh `homi` để tạo tập lệnh và tập tin cấu hình cho việc xây dựng L3. Bạn có thể chạy `homi` trên bất kỳ máy tính để bàn Linux/Mac nào. `chainID` của Baobab là `1001` và `chainID` của L2 được đặt thành `1002` trong ví dụ trước, vì vậy, để thuận tiện, `chainID` của L3 được đặt thành `1003`. Khi vận hành chuỗi khối cho một dịch vụ thực tế, bạn phải đăng ký giá trị `chainID` mới tại <https://chainlist.defillama.com/> để tránh xung đột `chainID` với các ServiceChain và chuỗi EVM khác.

```console
$ ./homi setup --gen-type local --cn-num 4 --test-num 1 --servicechain --chainID 1003 --p2p-port 22323 -o homi-output
Created :  homi-output/keys/passwd1
Created :  homi-output/keys/passwd2
Created :  homi-output/keys/passwd3
Created :  homi-output/keys/passwd4
Created :  homi-output/scripts/genesis.json
Created :  homi-output/keys/nodekey1
Created :  homi-output/keys/validator1
Created :  homi-output/keys/nodekey2
Created :  homi-output/keys/validator2
Created :  homi-output/keys/nodekey3
Created :  homi-output/keys/validator3
Created :  homi-output/keys/nodekey4
Created :  homi-output/keys/validator4
Created :  homi-output/scripts/static-nodes.json
Created :  homi-output/keys_test/testkey1
Created :  homi-output/keys_test/keystore1/0xdC7218621513f71d609653d22C39d79d558d9CDC
Created :  homi-output/Klaytn.json
Created :  homi-output/Klaytn_txpool.json
```

![](/files/5yDd8lIke2nUYWHn8OwE)

Cập nhật thông tin `địa chỉ IP` và `cổng` của các nút ServiceChain L3 trong `homi-output/scripts/static-nodes.json`.

```json
[
     "kni://358235ccbf97a1f...787f7@192.168.0.21:22323?discport=0&type=cn",
     "kni://14ac4e3d53de5c7...6c91d@192.168.0.22:22323?discport=0&type=cn",
     "kni://5f36a456d93da09...8e216@192.168.0.23:22323?discport=0&type=cn",
     "kni://d62fd0928b9b6e5...6badf@192.168.0.24:22323?discport=0&type=cn"
]
```

Sao chép `homi-output` vào tất cả các nút SCN (SCN-L3-01, SCN-L3-02, SCN-L3-03, SCN-L3-04) của ServiceChain L3.

```console
$ scp -r path/to/homi-output user@192.168.0.21:~/ 
$ scp -r path/to/homi-output user@192.168.0.22:~/ 
$ scp -r path/to/homi-output user@192.168.0.23:~/ 
$ scp -r path/to/homi-output user@192.168.0.24:~/ 
```

Khởi tạo tất cả các nút.

```console
$ kscn --datadir ~/data init ~/homi-output/scripts/genesis.json
$ ls ~/data
keystore    klay        kscn
```

Kết nối với tất cả các SCN (SCN-L3-01, SCN-L3-02, SCN-L3-03 và SCN-L3-04), sao chép `static-nodes.json` vào thư mục dữ liệu `~/data` và sao chép từng `khóa núts` một.

```console
$ cp   ~/homi-output/scripts/static-nodes.json   ~/data/
$ cp   ~/homi-output/keys/nodekey{1..4}   ~/data/klay/nodekey
```

### Bước 2: Định cấu hình SCN trong L3 <a href="#step-2-scn-configuration" id="step-2-scn-configuration"></a>

Chỉnh sửa `conf/kscnd.conf` trên tất cả các SCN trong ServiceChain L3 như sau: `PORT` sử dụng 22323, cổng mặc định của ServiceChain. `DATA_DIR` là `~/data`.

```
...
PORT=22323
...
DATA_DIR=~/data
...
```

Chạy ServiceChain trên tất cả các nút SCN trong L3 và kiểm tra xem nó có hoạt động bình thường không.

```console
$ kscnd start
Starting kscnd: OK
$ kscn attach --datadir ~/data
> klay.blockNumber
10
```

### Bước 3: Khởi động lại sau khi cài đặt cầu nối chính L2 <a href="#step-3-restart-after-setting-l2-main-bridge" id="step-3-restart-after-setting-l2-main-bridge"></a>

Kết nối với bảng điều khiển của nút SCN-L2-03, (Lưu ý: không phải L3 mà là L2) nút này sẽ đóng vai trò là cầu nối chính trong ServiceChain L2.

![](/files/q0XRVJz08yAexHvr8wGh)

Chỉnh sửa tập tin cấu hình kscn `conf/kscnd.conf` của SCN-L2-03 như sau.

```console
SC_MAIN_BRIDGE=1
```

Khởi động lại kscnd trên SCN-L2-03.

```console
SCN-L2-03$ kscnd stop
SCN-L2-03$ kscnd start
```

### Bước 4: Kiểm tra KNI của Nút cầu nối chính <a href="#step-4-check-kni-of-main-bridge-node" id="step-4-check-kni-of-main-bridge-node"></a>

Kiểm tra thông tin KNI của nút SCN-L2-03. Giá trị này sẽ được sử dụng để tạo tập tin `main-bridges.json` của nút SCN-L2-03, dùng để thiết lập cầu nối con trong ServiceChain L3.

![](/files/bzP9Ea8fa239wBIyT7en)

```console
SCN-L2-03$ kscn   attach   --datadir   ~/data
> mainbridge.nodeInfo.kni
"kni://87989a5a5dcc165...85b16b@[::]:50505?discport=0"
```

### Bước 5: Định cấu hình cầu nối con L3 <a href="#step-5-configure-l3-sub-bridge" id="step-5-configure-l3-sub-bridge"></a>

Kết nối với nút SCN-L3-01 sẽ tạo một cầu con của ServiceChain L3 (Lưu ý: không phải là L2). Tạo `main-bridges.json` trong thư mục `~/data`. Thay thế \[::] sau @ bằng địa chỉ IP của nút mà bạn đã kiểm tra ở bước 4.

```console
SCN-L3-01$ echo '["kni://87989a5a5dcc165...85b16b@192.168.0.13:50505?discport=0"]' > ~/data/main-bridges.json
```

Chỉnh sửa tập tin cấu hình `conf/kscnd.conf` của nút SCN-L3-01 với cầu nối con như sau. đặt `SC_SUB_BRIDGE` thành 1 để kích hoạt kết nối cầu nối và `SC_PARENT_CHAIN_ID` là `1002`, `chainID` của L2, Đặt `SC_ANCHORING` thành 1 để tự động neo dữ liệu khi khởi động lại. Bạn cũng có thể truy cập tập lệnh shell SCN-L3-01 và bật neo dữ liệu bằng lệnh `subbridge.anchoring(true)` hoặc tắt tính năng này bằng lệnh `subbridge.anchoring(false)`. `SC_ANCHORING_PERIOD` là tham số xác định tần suất gửi các giao dịch neo đến chuỗi mẹ. Đặt nút để neo sau mỗi 10 khối bằng cách đặt giá trị là 10. Mặc định là 1.

```console
SC_SUB_BRIDGE=1
…
SC_PARENT_CHAIN_ID=1002
…
SC_ANCHORING=1
SC_ANCHORING_PERIOD=10
```

Khởi động lại kscnd trên SCN-L3-01 sau khi hoàn tất thiết lập.

```console
SCN-L3-01$ kscnd stop
Shutting down kscnd: Killed
SCN-L3-01$ kscnd start
Starting kscnd: OK
```

Kiểm tra `subbridge.peers.length` để xem SCN-L3-01 có được kết nối với SCN-L2-03 hay không, kiểm tra `subbridge.latestAnchoredBlockNumber` để nắm được số khối được neo mới nhất để xem việc neo có đang được thực hiện hay không.

```console
SCN-L3-01$ kscn attach --datadir ~/data
> subbridge.peers.length
1
> subbridge.latestAnchoredBlockNumber
5010
```


# Chuyển giá trị giữa các chuỗi dịch vụ kết nối

Phần này sẽ giải thích cách bật tính năng chuyển giá trị giữa các mạng lưới ServiceChain. Các tính năng chính được cung cấp bởi ServiceChain như neo giữ dữ liệu và chuyển giá trị, có thể sử dụng độc lập. Nghĩa là, bạn chỉ có thể sử dụng tính năng neo dữ liệu hoặc là chuyển giá trị, bất kể bạn có sử dụng tính năng khác hay không.

Như minh họa trong hình bên dưới, nếu có hai ServiceChain (chainID 1002 và 1004) được kết nối với Baobab, vì mỗi servicechain thực hiện neo dữ liệu với Baobab, nên không cần neo dữ liệu giữa các chuỗi với nhau mà chỉ cần chuyển giá trị.

Để chuyển giá trị khi không có cầu nối giữa hai ServiceChain, trước tiên hãy chuyển giá trị từ ServiceChain (chainID 1002) sang Baobab (chainID 1001), rồi chuyển lại giá trị từ Baobab (chainID 1001) sang ServiceChain (chainID 1004). Điều này không hiệu quả bằng chuyển giá trị trực tiếp từ ServiceChain (chainID 1002) sang ServiceChain (chainID 1004) cùng lúc. Do đó, bằng cách tạo cầu nối trực tiếp giữa ServiceChain, chúng ta có thể chuyển giá trị một cách hiệu quả.

![](/files/F5160bcz2dqHCcV07m7t)

### Điều kiện tiên quyết <a href="#prerequisites" id="prerequisites"></a>

* Chúng tôi giả định rằng bạn đã cài đặt hai ServiceChain, mỗi servicechain được kết nối với EN Baobab. Tham khảo [Kết nối với Baobab](/content/installation-guide/deployment/service-chain/getting-started/en-scn-connection).
* Giả định rằng bạn đã thực hiện chuyển giá trị thông qua [Chuyển giá trị chuỗi chéo](/content/installation-guide/deployment/service-chain/getting-started/value-transfer).

Lặp lại [Kết nối với Baobab](/content/installation-guide/deployment/service-chain/getting-started/en-scn-connection) như trong hình trên để cài đặt thêm ServiceChain (chainID 1004).

Mỗi nút chỉ có thể có một cầu nối chính và một cầu nối con. Trong ví dụ này, để tiện giải thích, chúng ta sẽ kết nối một cầu nối với SCN-L2-03 và SCN-L2-07, đây là các nút chưa có cả cầu nối chính và cầu nối con.

![](/files/hu3rhGB9AIMUadkvbSlR)

### Bước 1: Kiểm tra KNI của nút SCN-L2-03 <a href="#step-1-check-kni-of-scn-node" id="step-1-check-kni-of-scn-node"></a>

Lưu ý KNI của SCN-L2-03 là thông tin được sử dụng để kết nối từ nút SCN. Giá trị này sẽ được sử dụng trong bước tiếp theo khi tạo `main-bridges.json`

```
SCN-L2-03$ kscn attach --datadir ~/data
> mainbridge.nodeInfo.kni
"kni://...39047242eb86278689...@[::]:50505?discport=0"
```

### Bước 2: Tạo main-bridges.json <a href="#step-2-create-main-bridges-json" id="step-2-create-main-bridges-json"></a>

Đăng nhập vào SCN-L2-07 (lưu ý: chainID 1004) và tạo `main-bridges.json` trên `~/data`. Thay thế `[::]` nằm sau chữ cái `@` bằng địa chỉ IP của nút EN.

```
$ echo '["kni://...39047242eb86278689...@192.168.0.3:50505?discport=0"]' > ~/data/main-bridges.json
```

### Bước 3: Định cấu hình SCN rồi Khởi động lại <a href="#step-3-configure-scn-then-restart" id="step-3-configure-scn-then-restart"></a>

Từ tập lệnh shell của nút SCN-L2-07, hãy chỉnh sửa `kscn-XXXXX-amd64/conf/kscnd.conf`. Vì mỗi ServiceChain đã được neo với EN Baobab nên không cần phải neo dữ liệu giữa chuỗi dịch vụ kết nối. Vì vậy, chúng ta đặt `SC_ANCHORING` thành 0.

```
...
SC_SUB_BRIDGE=1
...
SC_PARENT_CHAIN_ID=1002
...
SC_ANCHORING=0
...
```

Khởi động lại kscnd trên nút SCN-L2-07

```
SCN-L2-07$ kscnd stop
Shutting down kscnd: Killed
SCN-L2-07$ kscnd start
Starting kscnd: OK
```

Kiểm tra xem SCN-L2-07 có được kết nối với SCN-L2-0 hay không bằng cách kiểm tra `subbridge.peers.length`

```
SCN-L2-07$ kscn attach --datadir ~/data
> subbridge.peers.length
1
```

Trong trường hợp chuyển giá trị, nếu thông tin tương ứng với chainID 1002 được sử dụng làm thông tin cầu nối chính và thông tin tương ứng với chainID 1004 được đặt làm cầu nối con thì có thể chuyển giá trị giữa các chuỗi kết nối như trong [Chuyển giá trị chuỗi chéo](/content/installation-guide/deployment/service-chain/getting-started/value-transfer).


# Hướng dẫn sử dụng tham chiếu

## Đối tượng mục tiêu <a href="#intended-audience" id="intended-audience"></a>

* Các công ty muốn xây dựng blockchain cho Metaverse, GameFi và NFT
* Nhà phát triển dApp cần TPS cao, phí giao dịch tối thiểu và quyền riêng tư dữ liệu.
* Bất kỳ ai muốn xây dựng mạng lưới riêng tư cục bộ hoặc cơ sở dữ liệu sổ cái để thử nghiệm.

## Tổng quan về ServiceChain <a href="#service-chain-overview" id="service-chain-overview"></a>

ServiceChain là một blockchain cấp doanh nghiệp để đáp ứng các yêu cầu của công ty như chuyển giá trị, bảo mật, hiệu suất cao và tùy chỉnh. ServiceChain Klaytn cung cấp các tính năng sau:

* Tính hoàn thiện tức thời
* Chuyển token giữa các chuỗi Klaytin
* Neo dữ liệu vào chuỗi chính để đảm bảo tính toàn vẹn của dữ liệu
* Hợp đồng cầu nối đa chữ ký để đáp ứng các yêu cầu bảo mật cấp doanh nghiệp

![](/files/UxAlTrzneq7ti9Gn5Kv0)

Đọc [Giải pháp mở rộng Klaytn](/content/klaytn/scaling-solutions) để biết thêm chi tiết về ServiceChain. Các video sau đây sẽ giúp bạn hiểu rõ hơn về ServiceChain Klaytn.

* [Mở rộng quy mô theo chiều ngang thông qua Chuỗi dịch vụ trên Klaytn | TXGX 2019](https://www.youtube.com/watch?v=8yQc5FQysJc)
* [Kiến trúc có tính khả dụng cao của Chuỗi dịch vụ Klaytn | TXGX 2019](https://www.youtube.com/watch?v=HcdhWtXPuR0)


# Yêu cầu hệ thống

Các yêu cầu hệ thống phụ thuộc vào hiệu suất mà bạn hướng đến. Cho mục đích sử dụng thương mại, bạn có thể tham khảo các thông số kỹ thuật khuyến nghị cho Nút điểm cuối và Core Cell.

* [Yêu cầu hệ thống với Nút điểm cuối](/content/installation-guide/deployment/endpoint-node/system-requirements)
* [Yêu cầu hệ thống với Core Cell](/content/installation-guide/deployment/core-cell/system-requirements)


# Tải xuống

Bạn có thể nhận các gói cho SCN, SPN và SEN tại [trang tải về](/content/installation-guide/deployment/download).




---

[Next Page](/llms-full.txt/1)

