BlockChain: xây dựng ứng dụng DApp với Ethereum

BlockChain: xây dựng ứng dụng DApp với Ethereum

Rate this post

Trước khi bắt đầu phát triển DApp, chúng ta cần xác định trường hợp sử dụng cho DApp. Chúng tôi cũng cần xác định các thành phần khác nhau sẽ một phần của DApp của chúng tôi. Vì vậy, trước tiên chúng ta hãy làm điều này.

Trường hợp sử dụng cho DApp của chúng tôi là một ứng dụng bỏ phiếu có thể cho phép cử tri để bỏ phiếu cho một cuộc thăm dò được công bố trong phạm vi công cộng. Bỏ phiếu bằng cách sử dụng tập trung hệ thống không đáng tin cậy lắm, vì nó cho thấy một điểm duy nhất của lỗi dữ liệu và thất bại. Vì vậy, mục tiêu của DApp của chúng tôi là cho phép bỏ phiếu phi tập trung. 

Bằng cách này, mọi cử tri đều có quyền kiểm soát phiếu bầu của họ và mỗi phiếu bầu được xử lý trên mọi nút trên blockchain, do đó không có cách nào để xáo trộn phiếu bầu dữ liệu. Mặc dù điều này có thể dễ dàng thực hiện bằng cách sử dụng chuỗi khối Ethereum công khai, để làm cho bài tập của chúng tôi trở nên thú vị, chúng tôi sẽ triển khai DApp thăm dò ý kiến ​​của chúng tôi trên một mạng Ethereum riêng tư và vì điều đó, chúng tôi sẽ thiết lập mạng riêng quá. Nghe có vẻ thú vị? Làm thôi nào.

Bước đầu tiên sẽ là thiết lập một mạng Ethereum riêng tư. Sau đó lưu trữ logic kinh doanh và kết quả thăm dò ý kiến, chúng tôi sẽ tạo một hợp đồng thông minh sẽ được triển khai trên mạng Ethereum riêng tư này. Để tương tác với hợp đồng thông minh này, chúng tôi sẽ tạo một ứng dụng web giao diện người dùng bằng cách sử dụng thư viện web3. Đó là nó. Theo kế hoạch vừa mô tả, bài tập phát triển DApp của chúng tôi sẽ có các bước sau:

  1. Thiết lập mạng Ethereum riêng tư
  2. Tạo hợp đồng thông minh cho chức năng bỏ phiếu
  3. Triển khai hợp đồng thông minh cho mạng riêng
  4. Tạo một ứng dụng web giao diện người dùng để tương tác với hợp đồng thông minh

Trong các phần tiếp theo, chúng ta sẽ xem xét chi tiết từng các bước đã đề cập.

Lưu ý như đã đề cập, chúng ta cũng có thể sử dụng mạng ethereum công khai cho sự phát triển dapp này. thêm vào đó, chúng tôi cũng có thể sử dụng một số các công cụ như metamask và truffle framework để đẩy nhanh quá trình phát triển của một dapp ethereum. những công cụ này, cùng với nhiều công cụ khác, cho phép chúng tôi quản lý mã và triển khai của mình theo cách tốt hơn. 

Các bài viết liên quan:

Độc giả được khuyến khích khám phá những công cụ này và các công cụ khác để cố gắng tìm ra sự kết hợp để tạo ra một sự phát triển thoải mái và hiệu quả môi trường cho sự phát triển dapp của họ. văn bản này chủ yếu được tập trung vào về việc làm cho người đọc hiểu điều gì sẽ xảy ra khi tạo ra một dapp ethereum, do đó tất cả các công cụ cung cấp thông tin trừu tượng trên đầu của quá trình phát triển dapp được giữ ngoài phạm vi.

Thiết lập mạng ethereum riêng

Để thiết lập một mạng Ethereum riêng tư, chúng tôi sẽ cần một trong nhiều Có sẵn máy khách Ethereum. Nói một cách dễ hiểu, một ứng dụng khách Ethereum là một ứng dụng triển khai giao thức chuỗi khối Ethereum. Có nhiều ứng dụng khách Ethereum có sẵn trên Internet ngày nay; một trong những phổ biến một là go-ethereum, còn được gọi là geth. Chúng tôi sẽ sử dụng geth cho thiết lập mạng riêng. Đối với bài tập này, chúng tôi đang sử dụng một máy ảo đang chạy Ubuntu Linux phiên bản 16.04 

Cài đặt geth

Bước đầu tiên là cài đặt geth trên máy cục bộ của chúng tôi. Để cài đặt geth, chúng tôi sẽ tải trình cài đặt thực thi geth từ nguồn chính thức https: // geth. ethereum.org/downloads/. Trang tải xuống này tại trang web chính thức của geth liệt kê các gói trình cài đặt cho tất cả các nền tảng chính (Windows, macOS,Linux)

Tải xuống gói trình cài đặt cho nền tảng của bạn và cài đặt geth trên máy cục bộ của bạn. Bạn cũng có thể chọn cài đặt geth trên điều khiển từ xa (đám mây-lưu trữ) máy chủ / máy ảo nếu bạn không muốn cài đặt nó trên cục bộ của mình cỗ máy.

Khi geth được cài đặt thành công trên máy cục bộ của bạn, bạn có thể kiểm tra cài đặt bằng cách chạy lệnh sau trong terminal / dấu nhắc lệnh. phiên bản geth Tùy thuộc vào hệ điều hành nền tảng của bạn và phiên bản địa lý mà bạn có được cài đặt, lệnh này sẽ cung cấp một đầu ra tương tự như sau: 

Geth
Phiên bản: 1.7.3-ổn định
Cam kết Git: 4bb3c89d44e372e6a9ab85a8be0c9345265c763a
Kiến trúc: amd64
Phiên bản giao thức: [63 62]
Id mạng: 1
Phiên bản Go: go1.9
Hệ điều hành: linux
GOPATH =
GOROOT = / usr / lib / go-1.9

Tạo mục dữ liệu geth

Theo mặc định, geth sẽ có thư mục làm việc của nó nhưng chúng tôi sẽ tạo một tùy chỉnh một để chúng tôi có thể theo dõi nó một cách dễ dàng. Đơn giản chỉ cần tạo một thư mục và giữ đường dẫn đến thư mục này hữu ích.

Tạo tài khoản geth

Điều đầu tiên chúng ta cần là một tài khoản Ethereum có thể chứa Ether. Chúng tôi sẽ cần tài khoản này để tạo các hợp đồng và giao dịch thông minh của chúng tôi sau này phát triển DApp. Chúng tôi có thể tạo một tài khoản mới bằng cách sử dụng sau command.

sudo geth new --datadir <đường dẫn đến thư mục dữ liệu chúng tôi đã tạo ở bước trước>
sudo geth new --datadir / mygeth

Lưu ý Chúng tôi đang sử dụng sudo để tránh mọi vấn đề về quyền. Khi bạn chạy lệnh này, lời nhắc sẽ yêu cầu một cụm mật khẩu để khóa tài khoản này. Nhập và xác nhận cụm mật khẩu, sau đó tài khoản geth của bạn sẽ được tạo. Hãy nhớ ghi nhớ cụm mật khẩu bạn đã nhập; nó sẽ cần thiết để mở khóa tài khoản sau đó để ký kết các giao dịch. Địa chỉ của tài khoản này sẽ được hiển thị trên màn hình. Đối với chúng tôi, địa chỉ của tài khoản được tạo là baf735f889d603f0ec6b1030c91d9033e60525c3. Ảnh chụp màn hình sau 

BlockChain: xây dựng ứng dụng DApp với Ethereum

Hình 6-1. Thiết lập tài khoản Ethereum với geth

Lưu ý rằng chúng tôi đã chuyển thư mục dữ liệu làm tham số cho lệnh tạo tài khoản. Điều này là để đảm bảo rằng tệp chứa chi tiết tài khoản được tạo bên trong thư mục dữ liệu của chúng tôi để có thể dễ dàng truy cập tài khoản từ ngữ cảnh của thư mục này. Nếu chúng tôi không vượt qua tham số thư mục dữ liệu cho các lệnh geth, sau đó nó sẽ tự động lấy vị trí mặc định của thư mục dữ liệu (có thể khác tùy thuộc vào nền tảng).

Tạo tệp cấu hình genesis.json

Sau khi cài đặt geth và tạo tài khoản mới, bước tiếp theo là xác định

cấu hình genesis cho mạng riêng của chúng tôi. Như chúng ta đã thấy trong phần trước các chương, các blockchains có một khối genesis hoạt động như điểm bắt đầu của chuỗi khối và tất cả các giao dịch và khối được xác thực dựa trên

khối genesis. Đối với mạng riêng của chúng tôi, chúng tôi sẽ có một khối khởi thủy tùy chỉnh và do đó một cấu hình genesis tùy chỉnh. Cấu hình này xác định một số

các giá trị chính cho blockchain như mức độ khó, giới hạn gas cho các khối, v.v.

Cấu hình nguồn gốc cho Ethereum có định dạng sau như một đối tượng JSON. Mỗi khóa của đối tượng này là một giá trị cấu hình điều khiển mạng.

{
"config": {
"chainId": 3792,
"homesteadBlock": 0,
"eip155Block": 0,
"eip158Block": 0
},
"difficulty": "2000",
"gasLimit": "2100000",
"alloc": {
"baf735f889d603f0ec6b1030c91d9033e60525c3":
{ "balance": "9000000000000000000" }
}
}

Đối tượng JSON chủ yếu được cấu thành bởi một phần cấu hình có giá trị cụ thể cho chainId và số khối liên quan đến một số nhánh đã diễn ra. Tham số quan trọng cần lưu ý ở đây là chainId, đại diện cho định danh của blockchain và giúp ngăn chặn việc phát lại các cuộc tấn công. Đối với chuỗi riêng của chúng tôi, chúng tôi đã chọn chuỗi ngẫu nhiên 3792. 

Bạn có thể chọn bất kỳ số nào ở đây khác với các số được sử dụng bởi main lưới (1) và lưới thử nghiệm (2, 3 và 4). Thông số quan trọng tiếp theo là độ khó. Giá trị này xác định nó sẽ khó khăn như thế nào để khai thác một khối mới. Giá trị này cao hơn nhiều trong mạng chính Ethereum, nhưng đối với các mạng riêng, chúng ta có thể chọn giá trị tương đối nhỏ hơn.

Sau đó, có gasLimit . Đây là tổng giới hạn khí cho một khối chứ không phải Một giao dịch. Giá trị cao hơn thường có nghĩa là nhiều giao dịch hơn trong mỗi khối.

Cuối cùng, chúng ta có phần phân bổ. Sử dụng cấu hình này, chúng tôi có thể tiền hoàn lại tài khoản Ethereum với giá trị tính bằng wei. Như chúng ta thấy, chúng ta có đã tài trợ cho cùng một tài khoản Ethereum mà chúng tôi đã tạo ở bước cuối cùng, với 9 Ether.

Chạy nút đầu tiên của mạng riêng

Để chạy nút đầu tiên của blockchain riêng tư, trước tiên hãy sao chép JSON từ bước trước và lưu nó dưới dạng tệp có tên genesis.json. Vì đơn giản, chúng tôi đang lưu tệp này trong cùng một thư mục mà chúng tôi đang sử dụng làm thư mục dữ liệu cho geth.

Đầu tiên, chúng ta cần khởi tạo geth với genesis.json . Khởi tạo này là cần thiết để đặt cấu hình genesis tùy chỉnh cho mạng riêng của chúng tôi. Đĩa CD vào thư mục mà chúng tôi đã lưu tệp genesis.json là huyền thoại cd lệnh sau sẽ khởi tạo geth với tùy chỉnh cấu hình chúng tôi đã xác định.

sudo geth –datadir “/ mygeth” init genesis.json

geth sẽ xác nhận thiết lập cấu hình genesis tùy chỉnh với đầu ra trong ảnh chụp màn hình sau (Hình 6-2)

BlockChain: xây dựng ứng dụng DApp với Ethereum

Hình 6-2. Khởi tạo geth với cấu hình trong genesis.json

Tiếp theo, chúng ta cần chạy geth bằng lệnh sau và thông số. Chúng ta sẽ xem xét chi tiết từng thông số này

sudo geth --datadir "/mygeth" --networkid 8956 --ipcdisable
--port 30307 --rpc --rpcapi "eth,web3,personal,net,miner,admin, debug" --rpcport 8507 --mine --minerthreads=1 --etherbase=0xbaf 735f889d603f0ec6b1030c91d9033e60525c3

Hãy xem xét từng tham số mà chúng ta đã cung cấp cho lệnh geth.

datadir: Đây là để chỉ định thư mục dữ liệu giống như chúng tôi đã làm trong các bước trước.

networkid: Đây là định danh của mạng, phân biệt blockchain riêng tư của chúng tôi với các mạng Ethereum khác. Điều này tương tự như chainId mà chúng tôi đã xác định trong tệp genesis.json nhưng cung cấp một lớp khác biệt giữa mạng lưới. Như chúng ta có thể thấy, chúng tôi đã sử dụng một số tùy chỉnh cho giá trị này

ipcdisable: Với tham số này, chúng tôi đã vô hiệu hóa cổng giao tiếp liên quá trình cho geth so điều đó trong khi chạy nhiều phiên bản địa lý (nút) trên cùng một máy cục bộ mà chúng ta không nên gặp phải bất kỳ vấn đề xung đột nào.

port: Chúng tôi đã chọn một giá trị tùy chỉnh cho cổng để tương tác với geth.

rpc, –rpcapi, –rpcport: Ba tham số này xác định cấu hình cho API RPC được hiển thị bởi geth. Chúng tôi muốn kích hoạt nó; chúng tôi muốn eth, web3, perso API nal, net, miner, admin, debug geth bị lộ qua RPC; và chúng tôi muốn chạy nó trên cổng tùy chỉnh 8507.

mine – minerthreads – etherbase: Với những ba tham số chúng tôi đang hướng dẫn geth để bắt đầu nút này như một nút khai thác, giới hạn quy trình khai thác chủ đề chỉ một (để chúng tôi không tiêu thụ nhiều sức mạnh của CPU) và gửi phần thưởng khai thác đến Tài khoản Ethereum mà chúng tôi đã tạo ở bước đầu tiên. Đó là tất cả cấu hình chúng tôi cần tại thời điểm này để chạy geth đầu tiên của chúng tôi cho mạng riêng. 

Khi chúng tôi chạy lệnh này với tất cả các tham số, geth sẽ cung cấp cho đầu ra sau (như trong ảnh chụp màn hình trong Hình  6-3 )

BlockChain: xây dựng ứng dụng DApp với Ethereum

Hình 6-3. Geth chạy nút đầu tiên

Lưu ý câu lệnh nhật ký trình nghe UDP trong đầu ra.

INFO [02-11 | 18: 00: 57] UDP listener up
self = enode: // e03b50e9b1b2579904f2bbdff7dd0826bd4e4eb2e
225c1d1cb1a765195474d7418f3e8fbfeefd55bd85722973d1762
6f0e53208c62e38d1099bb583e702b3b48 @ [::]: 30307

Điều này chứa địa chỉ của nút mà chúng tôi vừa bắt đầu. Để kết nối khác đến nút này, chúng ta sẽ cần địa chỉ này. Hãy lưu ý nó ở một số địa điểm. Dòng sau có địa chỉ trích xuất từ ​​nhật ký trước tuyên bố.

enode: // e03b50e9b1b2579904f2bbdff7dd0826bd4e4eb2e225c1d1cb1a7 65195474d7418f3e8fbfeefd55bd85722973d17626f0e53208c62e38d1099
bb583e702b3b48 @ [::]: 30307

Lưu ý [::] trước số cổng mà chúng ta đã xác định trong lệnh. Hãy

thay thế địa chỉ này bằng địa chỉ IP máy chủ cục bộ nếu chúng tôi đang chạy nút khác trên cùng một máy hoặc thay thế bằng địa chỉ IP bên ngoài của máy. Vì chúng ta sẽ chạy nút mạng khác trên cùng một máy (cho mục đích phát triển), chúng tôi sẽ thay thế nó bằng localhost Địa chỉ IP. Vì vậy, địa chỉ của nút đầu tiên cuối cùng sẽ là

enode: // e03b50e9b1b2579904f2bbdff7dd0826bd4e4eb2e225c1d1cb1a
765195474d7418f3e8fbfeefd55bd85722973d17626f0e53208c62e38d10
99bb583e702b3b48@127.0.0.1: 30307

Chạy nút thứ 2 của mạng

Không có mạng nào chỉ có một nút; nó phải có ít nhất hai nút. Vì vậy, hãy chạy một phiên bản geth khác trên cùng một máy, điều này sẽ tương tác với nút mà chúng tôi vừa bắt đầu và cả hai nút này cùng nhau sẽ tạo thành mạng riêng Ethereum của chúng tôi. 

Để chạy một nút khác, trước hết chúng ta cần một thư mục khác có thể đặt làm thư mục dữ liệu của nút thứ hai. Hãy để chúng tôi tạo một cái. mkdir mygeth2

Bây giờ, chúng ta sẽ khởi tạo nút này với cùng một genesis.json cấu hình chúng tôi đã tạo cho nút đầu tiên. Hãy tạo một bản sao khác của cái này tệp genesis.json và lưu nó trong thư mục mới mà chúng tôi đã tạo trước đó. Hãy cũng CD vào thư mục này. Bây giờ, hãy khởi tạo cấu hình genesis cho nút thứ hai.

sudo geth –datadir “/ mygeth2” init genesis.json

Và, chúng ta sẽ nhận được một đầu ra tương tự như chúng ta đã nhận được cho nút đầu tiên. Xem

BlockChain: xây dựng ứng dụng DApp với Ethereum

Hình 6-4. Geth khởi tạo cấu hình cho nút thứ hai

Bây giờ nút thứ hai của chúng ta cũng được khởi tạo với cấu hình genesis. Hãy chạy nó. Để chạy nút thứ hai, chúng tôi sẽ chuyển một vài tham số khác nhau vào lệnh geth. Nút thứ hai này sẽ không chạy như một công cụ khai thác, vì vậy chúng tôi sẽ bỏ qua ba tham số cuối cùng khỏi lệnh mà chúng tôi đã cung cấp cho tham số đầu tiên nút. Ngoài ra, chúng tôi muốn hiển thị bảng điều khiển geth trong khi chạy nút này, vì vậy chúng tôi sẽ thêm một tham số cho điều đó. Lệnh chạy thứ hai nút sẽ là

sudo geth --datadir "/mygeth2" --networkid 8956 --ipcdisable --port 30308 --rpc --rpcapi "eth,web3,personal,net,miner,admin, debug" --rpcport 8508 console

Như chúng ta có thể thấy, thư mục dữ liệu và các cổng đã được thay đổi cho nút thứ hai. Chúng tôi cũng đã thêm cờ bảng điều khiển vào lệnh để chúng tôi có thể tải bảng điều khiển geth cho nút này. 

Khi chúng tôi chạy lệnh này, nút thứ hai cũng sẽ bắt đầu chạy và chúng ta sẽ thấy đầu ra sau đây trong thiết bị đầu cuối (Hình  6-5 )

BlockChain: xây dựng ứng dụng DApp với Ethereum

Hình 6-5. Geth chạy nút thứ hai

Tại thời điểm này, cả hai nút địa lý của chúng tôi đang chạy nhưng chúng không biết về nhau. Nếu chúng ta chạy admin.peers lệnh trên giao diện điều khiển geth của nút thứ hai, kết quả là chúng ta sẽ nhận được một mảng trống (Hình  6-6 )

BlockChain: xây dựng ứng dụng DApp với Ethereum

Hình 6-6. Bảng điều khiển Geth – kiểm tra các ứng dụng ngang hàng

Điều này có nghĩa là các nút không được kết nối với nhau. Hãy kết nối các nút. Để thực hiện việc này, chúng tôi sẽ gửi admin.addPeer () lệnh trên bảng điều khiển địa lý của nút thứ hai với địa chỉ nút của nút đầu tiên dưới dạng tham số. Hãy nhớ rằng chúng tôi đã lưu ý địa chỉ của nút đầu tiên sau khi chạy nó. Hãy chạy lệnh này trong nút thứ hai của bảng điều khiển geth. 

admin.addPeer ("enode: // e03b50e9b1b2579904f2bbdff7dd0826bd4e4e
b2e225c1d1cb1a765195474d7418f3e8fbfeefd55bd85722973d17626f0e5
3208c62e38d1099bb583e702b3b48@127.0.0.1: 30307 ")

Và ngay sau khi chúng tôi chạy lệnh này trên nút thứ hai, nó sẽ trả về thật. Ngoài ra, sau một vài giây, nó bắt đầu đồng bộ hóa với nút đầu tiên.

Ảnh chụp màn hình sau (Hình 6-7) hiển thị đầu ra này từ bảng điều khiển của nút thứ hai

BlockChain: xây dựng ứng dụng DApp với Ethereum

Hình 6-7. Bảng điều khiển Geth – thêm nút ngang hàng

Cả hai nút của chúng tôi hiện đã được kết nối và mạng Ethereum riêng tư của chúng tôi lên. Để xác minh thêm điều này, chúng tôi sẽ chạy lại lệnh admin.peers trên nút thứ hai và lần này chúng ta sẽ thấy mảng JSON với một đối tượng hiển thị nút đầu tiên là nút ngang hàng (Hình  6-8 )

BlockChain: xây dựng ứng dụng DApp với Ethereum

Hình 6-8. Bảng điều khiển Geth – kiểm tra các ứng dụng ngang hàng (một lần nữa)

Ảnh chụp màn hình sau đây cho thấy các cửa sổ đầu cuối của cả các nút mà chúng tôi đã thiết lập. Ở bên trái là nút đầu tiên, cũng là một công cụ khai thác và như chúng ta có thể thấy, nó liên tục khai thác các khối mới. Thư hai nút ở bên phải và chúng ta có thể thấy nó đang đồng bộ hóa với nút đầu tiên nút. Ảnh chụp màn hình (Hình  6-9) quá nhỏ để đọc vì quá nhiều thông tin trong đó, nhưng nó chỉ nắm bắt và hiển thị nhật ký từ cả hai Các nút Ethereum cạnh nhau

BlockChain: xây dựng ứng dụng DApp với Ethereum

Hình 6-9. Geth ghi nhật ký từ cả hai nút Ethereum

Bây giờ cả hai nút đều ngang hàng với nhau trong mạng, chúng ta có một chuỗi khối Ethereum riêng tư đang hoạt động với hai nút. Chúng tôi cũng có một Tài khoản Ethereum được thiết lập như một người khai thác và cũng được hoàn vốn trước bởi một số Số lượng Ether. Giờ đây, chúng tôi có thể tạo nhiều tài khoản hơn và chuyển Ether giữa các chúng trên blockchain riêng tư này.

Trong phần này, chúng ta đã học cách thiết lập một mạng Ethereum riêng tưvới hai nút. Đây có thể là bất kỳ số lượng nút nào; chúng ta chỉ cần làm theo quá trình tương tự cho mỗi nút mới. Trong trường hợp các nút ở xa, chúng ta nên hãy cẩn thận về việc chỉ định đúng địa chỉ IP của các máy từ xa và chúng tôi cũng nên đảm bảo rằng các cổng bắt buộc được mở nếu có tường lửa ngăn chặn lưu lượng truy cập vào máy

Tạo hợp đồng thông minh

Bây giờ chúng tôi đã thiết lập và hoạt động mạng Ethereum riêng tư, chúng tôi có thể chuyển sang bước tiếp theo là tạo hợp đồng thông minh cho cuộc thăm dò ý kiến chức năng của DApp của chúng tôi. Sau đó, chúng tôi sẽ triển khai hợp đồng này cho tư nhân của chúng tôimạng. Chúng tôi sẽ làm theo các bước tương tự để tạo và triển khai hợp đồng như chúng ta đã làm trong chương trước.

Hãy khởi động IDE trực tuyến Remix và viết mã hợp đồng thông minh của chúng tôi trong Solidity. Đoạn mã Solidity sau đây hiển thị hợp đồng thông minh mà chúng tôi có được mã hóa cho chức năng bỏ phiếu

pragma solidity ^0.4.19;
contract Poll {
event Voted(
address _voter,
uint _value
);
mapping(address => uint) public votes;
string pollSubject = "Should coffee be made tax free? Pass 1 for yes OR 2 for no in the vote function.";
function getPoll() constant public returns (string) { return pollSubject;
}
function vote(uint selection) public { Voted(msg.sender, selection);
require (votes[msg.sender] == 0); require (selection > 0 && selection < 3); votes[msg.sender] = selection;
}
}

Bây giờ, hãy phân tích mã nguồn hợp đồng này để hiểu những gì chúng tôi đã thực hiện ở đây. Như chúng ta có thể thấy, tên của hợp đồng là Poll.

Dòng mã tiếp theo là

event Voted(
address _voter,
uint _value
);

Đoạn mã trước về cơ bản là khai báo một hợp đồng thông minh sự kiện có hai tham số: một là loại địa chỉ Ethereum và một số khác thuộc loại số nguyên không dấu. Chúng tôi đã tạo ra sự kiện này để chúng tôi có thể nắm bắt được ai đã bình chọn những gì trong cuộc thăm dò. Chúng tôi sẽ trở lại đến điều này sau.

Tiếp theo, chúng tôi có

mapping(address => uint) public votes;

Dòng mã trước khai báo ánh xạ các địa chỉ Ethereum và số nguyên không dấu. Đây là kho dữ liệu nơi chúng tôi sẽ lưu trữ địa chỉ của cử tri và giá trị được lựa chọn của họ cho cuộc bỏ phiếu.

Sau đó, chúng tôi có những điều sau đây:

string pollSubject = "Should coffee be made tax free? Pass 1 for yes OR 2 for no in the vote function.";
function getPoll() constant public returns (string) { return pollSubject;
}

Đoạn mã trước đó đầu tiên khai báo một chuỗi cho cuộc thăm dò chủ thể. Trong điều này, chúng tôi đang đặt một câu hỏi của các cử tri. Và sau đó chúng tôi có một hàm có thể trả về giá trị của chuỗi này để những người bỏ phiếu có thể truy vấncuộc thăm dò nói về cái gì

Và cuối cùng, chúng tôi có chức năng thực hiện bỏ phiếu chức năng

function vote(uint selection) public { Voted(msg.sender, selection);

require (votes[msg.sender] == 0); require (selection > 0 && selection < 3); votes[msg.sender] = selection;

}

Kiểm tra kỹ từng dòng của đoạn mã trước đó. Đầu tiên, ngay sau khi chúng tôi nhập chức năng này, chúng tôi sẽ nâng cao sự kiện được bình chọn chúng tôi đã tạo với các giá trị của địa chỉ người gửi (người bỏ phiếu) và giá trị mà anh tađã được chọn lựa.

Tiếp theo, chúng tôi đang giới hạn một phiếu bầu cho mỗi cử tri bằng cách kiểm tra xem giá trị của phiếu bầu là 0 cho địa chỉ tương ứng trong ánh xạ. Yêu cầu câu lệnh được sử dụng để kiểm tra các điều kiện dựa trên đầu vào của người dùng. Và sau đó chúng tôi cũng đang hạn chế, bằng cách sử dụng câu lệnh request, giá trị của lựa chọn 1 hoặc 2. 1 là có và 2 là không. Và chúng tôi đã vượt qua những hướng dẫn trong chuỗi thăm dò ý kiến ​​để những người bỏ phiếu biết phải làm gì. Ảnh chụp màn hình trong Hình 6-10 cho thấy hợp đồng thông minh trong Remix, Chúng tôi đã biên soạn mã hợp đồng này bằng Remix và chúng tôi đã lấy ABI và mã byte cho hợp đồng để chúng tôi có thể triển khai nó vào mạng riêng của chúng tôi. Chúng tôi đã sao chép mã bytecode và ABI từ các phần tương ứng trong chi tiết cửa sổ bật lên của tab biên dịch Remix — chính xác cách chúng tôi đã thực hiện việc này trong phần trước chương

BlockChain: xây dựng ứng dụng DApp với Ethereum

Hình 6-10. Chỉnh sửa hợp đồng thông minh trong trình chỉnh sửa Solidity trực tuyến Remix

[
{
"constant": true,
"inputs": [
{
"name": "",
"type": "address"
}
],
"name": "votes",
"outputs": [
{
"name": "",
"type": "uint256"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{

"constant": true,

"inputs": [],

"name": "getPoll",

"outputs": [

{

"name": "",

"type": "string"

}

],

"payable": false,

"stateMutability": "view",

"type": "function"

},
{
"anonymous": false,
"inputs": [
{
"indexed": false,
"name": "_voter",
"type": "address"
},
{
"indexed": false,
"name": "_value",
"type": "uint256"
}
],
"name": "Voted",
"type": "event"
},
{
"constant": false,
"inputs": [
{
"name": "selection",
"type": "uint256"
}
],
"name": "vote",
"outputs": [],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
}
]

Với những giá trị này, hợp đồng thông minh của chúng tôi đã sẵn sàng được triển khai.

Lưu ý quan trọng có thể có một số cải tiến có thể được thực hiện để làm cho hợp đồng này an toàn và hiệu suất hơn ( khí ) thân thiện. mã Solidity không nên được coi là tài liệu tham khảo. chi tiết thảo luận về các phương pháp hay nhất về Solidity nằm ngoài phạm vi của văn bản này. Vì Các phương pháp hay nhất về solidity, chúng tôi khuyên bạn nên làm theo solidity chính thức tài liệu và văn bản cụ thể về Solidity.

Triển khai hợp đồng thông minh

Trong phần này, chúng tôi sẽ triển khai hợp đồng thông minh mà chúng tôi đã phát triển trong phần trước vào mạng Ethereum riêng tư mà chúng tôi đã tạo. Quá trình của triển khai hợp đồng thông minh giống như những gì chúng tôi đã làm trong phần trước chương. Sự khác biệt duy nhất là lần này chúng tôi đang triển khai hợp đồng với một mạng riêng thay vì một mạng công cộng. Trong chương này cũng vậy, chúng tôi đang sử dụng cùng một thư viện web3.js để lập trình Ethereum bằng cách sử dụng JavaScript. Chúng tôi khuyến nghị người đọc xem qua chương trước nếu

Thiết lập thư viện và kết nối web3s

Trước hết, chúng tôi sẽ cài đặt thư viện web3 trong ứng dụng node.js. Đây là chính xác cách chúng tôi đã làm trong chương trước. Ứng dụng node.js này sẽ được sử dụng để triển khai hợp đồng thông minh.

npm cài đặt web3@1.0.0-beta.28

Sau khi cài đặt, trước tiên hãy khởi tạo và khởi tạo phiên bản web3 .

var Web3 = request ('web3');
var web3 = new Web3 (Web3.providers mới.HttpProvider ('ht
tp: //127.0.0.1: 8507 '));

Lưu ý rằng lần này, nhà cung cấp HTTP của chúng tôi cho phiên bản web3 có đã thay đổi thành điểm cuối cục bộ thay vì điểm cuối INFURA công khai, chúng tôi đã sử dụng trong chương trước. Điều này là do chúng tôi hiện đang kết nối với mạng riêng nội bộ. Cũng lưu ý rằng cổng chúng tôi đang sử dụng là 8507, là những gì chúng tôi đã cung cấp trong tham số –rpcport khi chúng tôi thiết lập nút của mạng riêng của chúng tôi. Điều này có nghĩa là chúng tôi đang kết nối với nút của mạng từ phiên bản web3 của chúng tôi.

Triển khai hợp đồng với mạng riêng

Bây giờ chúng tôi đã có hợp đồng thông minh và các chi tiết của nó, chúng tôi sẽ chuẩn bị một web3 đối tượng hợp đồng với các chi tiết của hợp đồng này, và sau đó chúng tôi sẽ triển khai hợp đồng này với chuỗi khối Ethereum bằng cách gọi phương thức triển khai trên đối tượng hợp đồng.

Chúng ta cần tạo một đối tượng của lớp web3.eth.Contract có thể đại diện cho hợp đồng của chúng tôi.

 Đoạn mã sau tạo một hợp đồng ví dụ với ABI của hợp đồng của chúng tôi như một đầu vào cho phương thức khởi tạo.

var pollingContract = new web3.eth.Contract([
{
"constant": true,
"inputs": [
{
"name": "",
"type": "address"
}
],
"name": "votes",
"outputs": [
{
"name": "",
"type": "uint256"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "getPoll",
"outputs": [
{
"name": "",
"type": "string"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"anonymous": false,
"inputs": [
{
"indexed": false,
"name": "_voter",
"type": "address"
},
{
"indexed": false,
"name": "_value",
"type": "uint256"
}
],
"name": "Voted",
"type": "event"
},
{
"constant": false,
"inputs": [
{
"name": "selection",
"type": "uint256"
}
],
"name": "vote",
"outputs": [],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
}
]);

Bây giờ chúng ta cần triển khai hợp đồng này với mạng Ethereum bằng cách sử dụng phương pháp triển khai của thư viện web3. Đoạn mã sau đây cho thấy cách để làm điều này. Trong đoạn mã này, chúng tôi đã thêm mã byte vào trường dữ liệu của đối tượng được chuyển cho phương thức triển khai

Lưu ý rằng chúng tôi cũng đã sử dụng tài khoản mà chúng tôi đã tạo trong thiết lập mạng trong trường “từ” của chức năng gửi. Như tài khoản này được hoàn vốn trước với chín Ether và nó cũng được thêm vào làm tài khoản etherbase cho phần thưởng khai thác, nó có đủ Ether để triển khai hợp đồng. Toàn bộ chức năng để triển khai hợp đồng sẽ là 

var deployContract = function () {

var pollingContract = new web3.eth.Contract([{ "constant": true,

"inputs": [{
"name": "",
"type": "address"
}],
"name": "votes",
"outputs": [{
"name": "",
"type": "uint256"
}],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "getPoll",

"outputs": [{
"name": "",
"type": "string"
}],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"anonymous": false,
"inputs": [{
"indexed": false,
"name": "_voter",
"type": "address"
},
{
"indexed": false,
"name": "_value",
"type": "uint256"
}
],
"name": "Voted",
"type": "event"
},
{
"constant": false,
"inputs": [{
"name": "selection",
"type": "uint256"
}],
"name": "vote",

"outputs": [],

"payable": false,

"stateMutability": "nonpayable",

"type": "function"

}

]);

Sau khi thực thi chức năng này từ ứng dụng node.js của chúng tôi, chúng tôi đã nhận được đầu ra sau

Contract {
currentProvider: [Getter/Setter], _requestManager:
RequestManager {
provider: null,
providers:
{ WebsocketProvider: [Function: WebsocketProvider], HttpProvider: [Function: HttpProvider], IpcProvider: [Function: IpcProvider] },
subscriptions: {} },
givenProvider: null,
providers:
{ WebsocketProvider: [Function: WebsocketProvider], HttpProvider: [Function: HttpProvider], IpcProvider: [Function: IpcProvider] },
_provider: null,
setProvider: [Function], BatchRequest: [Function: bound Batch], extend:
{ [Function: ex] formatters:
{ inputDefaultBlockNumberFormatter: [Function: inputDefaultBlockNumberFormatter],
inputBlockNumberFormatter: [Function: inputBlockNumberFormatter], inputCallFormatter: [Function: inputCallFormatter], inputTransactionFormatter: [Function: inputTransactionFormatter], inputAddressFormatter: [Function: inputAddressFormatter],
inputPostFormatter: [Function: inputPostFormatter],
inputLogFormatter: [Function: inputLogFormatter],
inputSignFormatter: [Function: inputSignFormatter],
outputBigNumberFormatter: [Function: outputBigNumberFormatter], outputTransactionFormatter: [Function: outputTransactionFormatter], outputTransactionReceiptFormatter: [Function: outputTransactionReceiptFormatter], outputBlockFormatter: [Function: outputBlockFormatter], outputLogFormatter: [Function: outputLogFormatter], outputPostFormatter: [Function: outputPostFormatter], outputSyncingFormatter: [Function: outputSyncingFormatter] },
utils:

{ _fireError: [Function: _fireError], _jsonInterfaceMethodToString: [Function: _jsonInterfaceMethodToString], randomHex: [Function: randomHex],
_: [Function],
BN: [Function],
isBN: [Function: isBN],
isBigNumber: [Function: isBigNumber],
isHex: [Function: isHex],
isHexStrict: [Function: isHexStrict],
sha3: [Function],
keccak256: [Function],
soliditySha3: [Function: soliditySha3],
isAddress: [Function: isAddress],
checkAddressChecksum: [Function: checkAddressChecksum],
toChecksumAddress: [Function: toChecksumAddress],
toHex: [Function: toHex],
toBN: [Function: toBN],
bytesToHex: [Function: bytesToHex],
hexToBytes: [Function: hexToBytes],
hexToNumberString: [Function: hexToNumberString],
hexToNumber: [Function: hexToNumber],
toDecimal: [Function: hexToNumber],
numberToHex: [Function: numberToHex],
fromDecimal: [Function: numberToHex],
hexToUtf8: [Function: hexToUtf8],
hexToString: [Function: hexToUtf8],
toUtf8: [Function: hexToUtf8],
utf8ToHex: [Function: utf8ToHex],
stringToHex: [Function: utf8ToHex],
fromUtf8: [Function: utf8ToHex],
hexToAscii: [Function: hexToAscii],
toAscii: [Function: hexToAscii],
asciiToHex: [Function: asciiToHex],
fromAscii: [Function: asciiToHex],
unitMap: [Object],
toWei: [Function: toWei],
fromWei: [Function: fromWei],
padLeft: [Function: leftPad],
leftPad: [Function: leftPad],
padRight: [Function: rightPad],
rightPad: [Function: rightPad],
toTwosComplement: [Function: toTwosComplement] },
Method: [Function: Method] }, clearSubscriptions: [Function], options:
{ address: [Getter/Setter], jsonInterface: [Getter/Setter], data: undefined,
from: undefined,
gasPrice: undefined,
gas: undefined }, defaultAccount: [Getter/Setter], defaultBlock: [Getter/Setter], methods:
{ votes: [Function: bound _createTxObject], '0xd8bff5a5': [Function: bound _createTxObject], 'votes(address)': [Function: bound _createTxObject], getPoll: [Function: bound _createTxObject], '0x03c32278': [Function: bound _createTxObject], 'getPoll()': [Function: bound _createTxObject],
vote: [Function: bound _createTxObject],
'0x0121b93f': [Function: bound _createTxObject],
'vote(uint256)': [Function: bound _createTxObject] }, events:
{ Voted: [Function: bound ],
'0x4d99b957a2bc29a30ebd96a7be8e68fe50a3c701db28a91436
490b7d53870ca4': [Function: bound ],
'Voted(address,uint256)': [Function: bound ],
allEvents: [Function: bound ] },
_address: '0x59E7161646C3436DFdF5eBE617B4A172974B481e', _jsonInterface:
[ { constant: true,
inputs: [Array],
name: 'votes',
outputs: [Array],
payable: false,
stateMutability: 'view',
type: 'function',
signature: '0xd8bff5a5' },
{ constant: true, inputs: [], name: 'getPoll', outputs: [Array], payable: false, stateMutability: 'view', type: 'function', signature: '0x03c32278' },
{ anonymous: false, inputs: [Array], name: 'Voted', type: 'event',
signature: '0x4d99b957a2bc29a30ebd96a7be8e68fe50a3c70 1db28a91436490b7d53870ca4' },
{ constant: false, inputs: [Array], name: 'vote', outputs: [], payable: false, stateMutability: 'nonpayable', type: 'function', signature: '0x0121b93f' } ] 
}

Kết quả hiển thị các thuộc tính khác nhau của hợp đồng mà chúng tôi được triển khai vào mạng riêng của chúng tôi. Điều quan trọng nhất là địa chỉ hợp đồng mà tại đó hợp đồng được triển khai, đó là

0x59E7161646C3436DFdF5eBE617B4A172974B481e.

Hợp đồng ABI và địa chỉ có thể được sử dụng để gọi một hàm trên hợp đồng. Trong phần tiếp theo, chúng tôi sẽ xây dựng một ứng dụng web đơn giản sẽ gọi chức năng bỏ phiếu của hợp đồng này, giới thiệu cách thực hiện cuộc bỏ phiếu từ giao diện người dùng

Tạo một ứng dụng web giao diện người dùng để tương tác với hợp đồng thông minh

Như chúng ta đã làm trong chương trước, chúng ta có thể sử dụng thư viện web3 để gọi một hàm trên hợp đồng thông minh. Tuy nhiên, trong chương trước, chúng ta đã làm điều đó bằng ứng dụng node.js chứ không phải trong ứng dụng trình duyệt. Trong phần này, chúng tôi sẽ sử dụng web3 trong một ứng dụng trình duyệt để gọi chức năng bỏ phiếu của hợp đồng thông minh đã triển khai của chúng tôi.

Ứng dụng web đơn giản nhất mà chúng tôi có thể tạo cho DApp này là một trang web duy nhất với một vài điều khiển văn bản và nút. Đối với trang web, chúng tôi có thể sử dụng mã sau bên trong tệp html và sau đó chạy nó từ máy chủ cục bộ. Lưu ý rằng việc chạy từ một máy chủ cục bộ và không trực tiếp mở tệp từ trình duyệt là điều quan trọng để tải các tập lệnh đúng cách mà không gặp phải bất kỳ vấn đề bảo mật nào của trình duyệt.

<html>
<c>
<meta charset="UTF-8">
<title>Beginning Blockchain - DApp demo</title>
<script src="<source of web3 library from any CDN or local file>"></script>
</head>
<body>
<div>
<p>
<strong>Beginning Blockchain</strong>
</p>
<p>Hi, Welcome to the Polling DApp!</p> <p>&nbsp;</p>
<p>Get latest poll:&nbsp;
<button onclick="getPoll()">Get Poll</button>
</p>
<p>
<div id="pollSubject"></div>
</p>
<p>Vote: Yes:
<input type="radio" id="yes"> No:
<input type="radio" id="no">
</p>
<p>Submit:&nbsp;
<button onclick="submitVote()">Submit Vote</button>
</p>
</p>
</div>
<script>
if (typeof web3 !== 'undefined') {
web3 = new Web3(web3.currentProvider); } else {
web3 = new Web3(new Web3.providers.HttpProvider ('http://127.0.0.1:8507'));
}
function getPoll() {
var pollingContract = new web3.eth.Contract([{ "constant": true,
"inputs": [{
"name": "",
"type": "address"
}],
"name": "votes",
"outputs": [{
"name": "",
"type": "uint256"
}],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "getPoll",
"outputs": [{
"name": "",
"type": "string"
}],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"anonymous": false,
"inputs": [{
"indexed": false,
"name": "_voter",
"type": "address"
},
{
"indexed": false,
"name": "_value",
"type": "uint256"
}
],
"name": "Voted",
"type": "event"
},
{
"constant": false,
"inputs": [{
"name": "selection",
"type": "uint256"
}],
"name": "vote",
"outputs": [],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
}
], '0x59E7161646C3436DFdF5eBE617B4A172974B481e');
pollingContract.methods.getPoll().call().
then(function (value) {
document.getElementById('pollSubject').
textContent = value;
});
};
function submitVote() {
var value = 0
var yes = document.getElementById('yes').checked; var no = document.getElementById('no').checked;
if (yes) {
value = 1
} else if (no) { value = 2
} else { return;
}
var pollingContract = new web3.eth.Contract([{ "constant": true,
"inputs": [{
"name": "",
"type": "address"
}],
"name": "votes",
"outputs": [{
"name": "",
"type": "uint256"
}],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "getPoll",
"outputs": [{
"name": "",
"type": "string"
}],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"anonymous": false,
"inputs": [{
"indexed": false,
"name": "_voter",
"type": "address"
},
{
"indexed": false,
"name": "_value",
"type": "uint256"
}
],
"name": "Voted",
"type": "event"
},
{
"constant": false,
"inputs": [{
"name": "selection",
"type": "uint256"
}],
"name": "vote",
"outputs": [],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
}
], '0x59E7161646C3436DFdF5eBE617B4A172974B481e');
pollingContract.methods.vote(value).send({ from: '0xbaf735f889d603f0ec6b1030c91d9033e 60525c3'
}).then(function (result) {
console.log(result);
});
};
</script>
</body>
</html>

Bây giờ chúng ta hãy phân tích từng phần của tệp HTML này.

Trong phần đầu của tài liệu HTML, chúng tôi đã tải tập lệnh web3 từ nguồn CDN hoặc nguồn cục bộ. Điều này giống như chúng tôi tham chiếu đến bất kỳ thư viện JavaScript bên thứ ba nào khác trong các trang web của chúng tôi (JQuery, v.v.)

Sau đó, trong phần nội dung của HTML, chúng tôi có các điều khiển để hiển thị chủ đề cuộc thăm dò ý kiến ​​và các nút radio và gửi để nắm bắt thông tin đầu vào của người dùng. Tổng thể trang web trông như thế này (Hình 6-11 ).

BlockChain: xây dựng ứng dụng DApp với Ethereum

Điều quan trọng là phần script trong body. Đó là nơi chúng tôi đang gọi là mã tương tác hợp đồng thông minh. Chúng ta hãy nhìn vào nó một cách chi tiết.

<script>
 
if (typeof web3 !== 'undefined') {
 
web3 = new Web3(web3.currentProvider); } else {
 
web3 = new Web3(new Web3.providers.HttpProvider ('http://127.0.0.1:8507'));
 
}
 
function getPoll() {
 
var pollingContract = new web3.eth.Contract([{ "constant": true,
 
"inputs": [{
 
"name": "",
 
"type": "address"
 
}],
 
"name": "votes",
 
"outputs": [{
 
"name": "",
 
"type": "uint256"
 
}],
 
"payable": false,
 
"stateMutability": "view",
 
"type": "function"
 
},
 
{
 
"constant": true,
 
"inputs": [],
 
"name": "getPoll",
 
"outputs": [{
 
"name": "",
 
"type": "string"
 
}],
 
"payable": false,
 
"stateMutability": "view",
 
"type": "function"
 
},
 
{
 
"anonymous": false,
 
"inputs": [{
 
"indexed": false,
 
"name": "_voter",
 
"type": "address"
 
},
{
 
"indexed": false,
 
"name": "_value",
 
"type": "uint256"
 
}
 
],
 
"name": "Voted",
 
"type": "event"
 
},
 
{
 
"constant": false,
 
"inputs": [{
 
"name": "selection",
 
"type": "uint256"
 
}],
 
"name": "vote",
 
"outputs": [],
 
"payable": false,
 
"stateMutability": "nonpayable",
 
"type": "function"
 
}
 
], '0x59E7161646C3436DFdF5eBE617B4A172974B481e');
 
pollingContract.methods.getPoll().call().
 
then(function (value) {
 
document.getElementById('pollSubject').
 
textContent = value;
 
});
 
};
function submitVote() {
 
var value = 0
 
var yes = document.getElementById('yes').checked; var no = document.getElementById('no').checked;
 
if (yes) {
 
value = 1
 
} else if (no) { value = 2
 
} else {
 
return;
 
}
 
var pollingContract = new web3.eth.Contract([{ "constant": true,
 
"inputs": [{
 
"name": "",
 
"type": "address"
 
}],
 
"name": "votes",
 
"outputs": [{
 
"name": "",
 
"type": "uint256"
 
}],
 
"payable": false,
 
"stateMutability": "view",
 
"type": "function"
 
},
 
{
 
"constant": true,
 
"inputs": [],
 
"name": "getPoll",
"outputs": [{
 
"name": "",
 
"type": "string"
 
}],
 
"payable": false,
 
"stateMutability": "view",
 
"type": "function"
 
},
 
{
 
"anonymous": false,
 
"inputs": [{
 
"indexed": false,
 
"name": "_voter",
 
"type": "address"
 
},
 
{
 
"indexed": false,
 
"name": "_value",
 
"type": "uint256"
 
}
 
],
 
"name": "Voted",
 
"type": "event"
 
},
 
{
 
"constant": false,
 
"inputs": [{
 
"name": "selection",
 
"type": "uint256"
 
}],
 
"name": "vote",
 
"outputs": [],
"payable": false,
 
"stateMutability": "nonpayable",
 
"type": "function"
 
}
 
], '0x59E7161646C3436DFdF5eBE617B4A172974B481e');
 
pollingContract.methods.vote(value).send({ from: '0xbaf735f889d603f0ec6b1030c91d9033 e60525c3'
 
}).then(function (result) {
 
console.log(result);
 
});
 
};

 
</script>

Trong phần tập lệnh trước, đầu tiên chúng ta đang khởi tạo đối tượng web3 với nhà cung cấp HTTP của nút Ethereum cục bộ (nếu nó chưa được khởi tạo).

Sau đó, chúng ta có hai hàm JavaScript. Một để lấy giá trị của chuỗi thăm dò ý kiến từ hợp đồng thông minh và một để gọi chức năng bỏ phiếu của hợp đồng.

Việc gọi các hàm hợp đồng thông minh chính xác là cách chúng ta đã thực hiện trong chương trước bằng cách sử dụng mô-đun con web3.eth.Contract của thư viện web3 .

Lưu ý rằng trong hàm đầu tiên getPoll, chúng ta đang gọi hàm gọi trên cá thể hợp đồng thông minh, trong khi ở hàm thứ hai submitVote, chúng ta đang gọi gửi trên cá thể hợp đồng thông minh. Đó chủ yếu là sự khác biệt trong hai lệnh gọi hàm.

Sử dụng cuộc gọi trên getPoll chức năng của hợp đồng thông minh, chúng tôi đang nhận được giá trị trả về của hàm getPoll mà không gửi bất kỳ giao dịch vào mạng. Sau đó, chúng tôi hiển thị giá trị này trên giao diện người dùng bằng cách chỉ định giá trị này dưới dạng văn bản của phần tử giao diện người dùng.

Tiếp theo, sử dụng gửi trên phiếu bầu chức năng, chúng tôi đang gửi một giao dịch để thực hiện chức năng này trên mạng và vì vậy chúng tôi cũng đã xác định một tài khoản đó sẽ được sử dụng để thực hiện các chức năng đồng thông minh. Sau đây là kết quả thu được từ hàm submitVote được hiển thị trước đó, về cơ bản nó là một biên lai giao dịch.

{
 
blockHash: '0x04a02dd56c037569eb6abe25e003a65d3366407 134c90a056f64b62c2d23eb84', blockNumber: 4257,
 
contractAddress: null,
 
cumulativeGasUsed: 43463,
 
from: '0xbaf735f889d603f0ec6b1030c91d9033e60525c3',
 
gasUsed: 43463,
 
logsBloom: '0x000000000000000000000000000000800000000 00000040000000000000000000200000000000000000000000000 00000000000000000000000000000000000000000000000000000 00000000000200000000002000000000000000000000000000000 00000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000002000000000000000 00000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000', root: '0x58bc4ee0a3025ca3f303df9bb243d052a123026519637 30c52c88aafe92ebeee',
 
to: '0x59e7161646c3436dfdf5ebe617b4a172974b481e', transactionHash: '0x434aa9c0037af3367a0d3d92985781c50 774241ace1d382a8723985efcea73b3', transactionIndex: 0,
events: {
 
Voted: {
 
address: '0x59E7161646C3436DFdF5eBE617B4A17
 
2974B481e',
 
blockNumber: 4257,
 
transactionHash: '0x434aa9c0037af3367a0d3d929 85781c50774241ace1d382a8723985efcea73b3', transactionIndex: 0,
 
blockHash: '0x04a02dd56c037569eb6abe25e003a65
 
d3366407134c90a056f64b62c2d23eb84',
 
logIndex: 0,
 
removed: false,
 
id: 'log_980a1744',
 
returnValues: [Result],
 
event: 'Voted',
 
signature: '0x4d99b957a2bc29a30ebd96a7be8e68f e50a3c701db28a91436490b7d53870ca4', raw: [Object]
 
}
 
}
 
}

Nếu chúng ta xem xét kỹ kết quả này, chúng ta thấy rằng phần này cũng có một phần sự kiện và nó cho thấy việc kích hoạt sự kiện Được bình chọn mà chúng tôi đã tạo trong hợp đồng thông minh của mình.

events: {
 
Voted: {
 
address: '0x59E7161646C3436DFdF5eBE617B4A172
 
974B481e',
 
blockNumber: 4257,
 
transactionHash: '0x434aa9c0037af3367a0d3d929 85781c50774241ace1d382a8723985efcea73b3',
transactionIndex: 0,
 
blockHash: '0x04a02dd56c037569eb6abe25e003a6
 
5d3366407134c90a056f64b62c2d23eb84',
 
logIndex: 0,
 
removed: false,
 
id: 'log_980a1744',
 
returnValues: [Result],
 
event: 'Voted',
 
signature: '0x4d99b957a2bc29a30ebd96a7be8e68fe 50a3c701db28a91436490b7d53870ca4', raw: [Object]
 
}
 
}

Trong đoạn mã trước, chúng tôi đã trích xuất phần sự kiện từ biên lai giao dịch mà chúng tôi nhận được trong phản hồi của giao dịch gửi đến chức năng bỏ phiếu trong hợp đồng thông minh của chúng tôi. Như chúng ta có thể thấy, phần sự kiện cũng hiển thị các giá trị trả về và giá trị thô từ lệnh gọi hàm.

Bây giờ chúng ta đã đến phần cuối của bài tập lập trình DApp của chúng ta. Trong các phần trước của chương này, chúng tôi đã phát triển một ứng dụng phi tập trung đầu cuối trên chuỗi khối Ethereum và chúng tôi cũng triển khai một chuỗi khối riêng cho DApp của mình.

DApp cũng có thể được sử dụng với mạng Ethereum công cộng — người bỏ phiếu phải lưu trữ một nút và họ có thể bỏ phiếu bằng tài khoản Ethereum hiện có của họ trên mạng công cộng (chính).

Có thể có một số cách trong đó logic kinh doanh trong hợp đồng thông minh có thể được nâng cao bằng cách sử dụng các quy tắc và kiểm tra khác nhau.

Bài tập lập trình này cung cấp cho chúng ta ý tưởng cơ bản về cách tiếp cận sự phát triển của các ứng dụng phi tập trung và các thành phần

Leave a Reply