Tải bản đầy đủ (.docx) (35 trang)

BÁO cáo môn học KIẾN TRÚC PHÁT TRIỂN HPT đề tài xây dựng marketplace trên nền tảng ethereum

Bạn đang xem bản rút gọn của tài liệu. Xem và tải ngay bản đầy đủ của tài liệu tại đây (468.94 KB, 35 trang )

ĐẠI HỌC ĐÀ NẴNG

TRƯỜNG ĐẠI HỌC BÁCH KHOA

KHOA KHOA HỌC CÔNG NGHỆ TIÊN TIẾN

BÁO CÁO MÔN HỌC
KIẾN TRÚC & PHÁT TRIỂN HPT
ĐỀ TÀI :

Xây dựng Marketplace trên nền tảng Ethereum

GVHD:
Lớp:
SVTH:

PGS. TS Nguyễn Tấn Khơi
18PFIEV3
Nhóm 4
Võ Trần Anh Khoa
Đào Thị Thúy Ngân
Kiều Thị Phượng

Đà Nẵng, tháng 12 năm 2022


MỤC LỤC
>> Chú ý: Trong mục lục chỉ nên liệt kê Heading 1, 2, 3
CHƯƠNG 1: CƠ SỞ LÝ THUYẾT
1.1. website website?
1.2. BLOCKCHAIN


1.2.1. BLOCKCHAIN
1.3. PHÁT BIỂU BÀI TOÁN
1.4. KẾT CHƯƠNG

2
3
3
3
3
3

CHƯƠNG 2: PHÂN TÍCH THIẾT KẾ HỆ THỐNG
2.1. PHÂN TÍCH HIỆN TRẠNG
2.2. PHÂN TÍCH YÊU CẦU
2.3. PHÂN TÍCH CHỨC NĂNG
2.3.1. Đối tượng sử dụng
2.3.2. Công nghệ sử dụng:
2.4. TỔ CHỨC CHƯƠNG TRÌNH
2.4.1. Tổ chức thư mục
2.4.2. Tập tin 01
2.4.3. Tập tin 02
2.4.4. Tập tin 03
2.5. KẾT CHƯƠNG

3
4
4
4
4
4

4
4
4
4
4
4

CHƯƠNG 3: TRIỂN KHAI VÀ ĐÁNH GIÁ KẾT QUẢ
3.1. MƠ HÌNH TRIỂN KHAI
3.1.1. Mơ hình triển khai
3.1.2. Cấu hình hệ thống:
3.1.2.1. Chức năng bán sản phẩm:
3.1.2.2. Chức năng mua sản phẩm:
3.1.2.3. Xây dựng trang web Marketplace: (Frontend)
3.2. KẾT QUẢ THỰC NGHIỆM
3.2.1. Khởi động hệ thống
3.2.2. Chức năng kết nối với MetaMask:
3.2.3. Kịch bản 3 – Chức năng tìm kiếm, thống kê
3.2.4. Kịch bản 4 – Chức năng truy vấn, báo cáo
3.3. NHẬN XÉT ĐÁNH GIÁ KẾT QUẢ
3.4. KẾT CHƯƠNG

4
5
5
5
5
6
7
16

16
18
18
18
18
18

2


DANH SÁCH HÌNH ẢNH
>> Canh dịng: 1.5 line

DANH SÁCH TỪ VIẾT TẮT
Từ viết tắt

Diễn giải

IP

Internet Protocol

MD5

Message-Degist Algorithm 5

SHA

Secure Hash Algorithm


API

Application Programming Interface

URL

Uniform Resource Locator


MỞ ĐẦU
1. Tổng quan về đề tài
Công nghệ blockchain đang đóng vai trị to lớn đến nền kinh tế tồn cầu,
thương mại điện tử cũng đang đón nhận nhiều sự chú ý trong những năm gần đây.
Hiện nay đã có hơn 22,000 cửa hàng nhỏ lẻ trên toàn thế giới cho phép khách hàng
thanh toán bằng tiền điện tử (crypto). Khi ứng dụng blockchain vào thương mại
điện tử, blockchain không chỉ tạo ra cơ hội cho doanh nghiệp rút gọn quy trình kinh
doanh, tiết kiệm chi phí mà cịn nâng cao bảo mật dữ liệu và trải nghiệm khách
hàng.
Do đó, nhóm thực hiện/ triển khai …
Phần này trình bày tổng quan, tính cấp thiết của đề tài, các vấn đề quan
trọng cần giải quyết.
2. Mục đích và ý nghĩa của đề tài
2.1. Mục đích
Đề tài này được thực hiện với mục đích xây dựng một kênh mua bán sản
phẩm trên nền tảng web và có thể thực hiện thanh tốn bằng Ethereum.
2.2. Ý nghĩa
-

Giúp bảo mật ..


3. Phương pháp thực hiện
Đồ án này xây dựng một website với:
-

Ngôn ngữ lập trình: HTML, CSS, JavaScript, Solidity

-

Thư viện hỗ trợ: Bootstrap, Web3.js, React.js

-

Framework: Truffle, Ethereum

-

Cơng cụ lập trình: Visual Studio Code

-

Cơng cụ hỗ trợ: Ganache, Node Package Manager

4. Bố cục của đồ án
4


Đồ án bao gồm các nội dung sau:
-

Mở đầu: gồm phần tổng quan về đề tài, mục đích, ý nghĩa và phương pháp

thực hiện đề tài.

-

Chương 1: trình bày nội dung cơ sở lý thuyết chính liên quan đến nội dung
của đồ án.

-

Chương 2: trình bày trình bày về phân tích và thiết kế hệ thống.

-

Chương 3: trình bày về kết quả triển khai hệ thống và các thành phần chức
năng.

-

Kết luận và hướng phát triển.


CHƯƠNG 1:

CƠ SỞ LÝ THUYẾT

Chương này trình bày các nội dung cơ sở lý thuyết chính liên quan đến nội
dung của đồ án. Nội dung cơ sở lý thuyết này sẽ được sử dụng trong phần phân tích
và triển khai chương trình. Phần phát biểu bài tốn sẽ mơ tả nội dung và các vấn
đề đặt ra. Ngoài ra cũng liệt kê và đánh giá các giải pháp đã có.
1.1. website website?

Hình 1.1 xxx
1.2. BLOCKCHAIN
1.2.1. Blockchain
Blockchain là một hệ thống sổ cái an toàn và bảo mật tuyệt đối giúp lưu trữ
tồn bộ thơng tin giao dịch được thực hiện tại một thời gian cụ thể.
Công nghệ blockchain giúp người dùng có thể chia sẻ và lưu trữ các tài sản số
hố, ngồi ra có thể ứng dụng để xử lý thanh tốn hay tìm kiếm sản phẩm.
1.2.2. Ethereum
Sau sự thành công của Bitcoin, một loại tiền điện tử khác cũng gây tiếng vang
trong thị trường số hiện nay là Ethereum. Ethereum cho phép mọi người xây dựng
và sử dụng các ứng dụng phi tập trung dựa trên công nghệ Blockchain. Nó là dự án
mã nguồn mở, có thể chuyển đổi và linh hoạt hơn Bitcoin.
Ethereum có các đặc điểm sau:
-

Là mạng mở;

-

Sử dụng mơ hình đồng thuận bằng chứng cơng việc;

-

Có lượng người theo dõi trên Github cao;

-

Hỗ trợ các ngôn ngữ như C++, Go và Python

1.3. PHÁT BIỂU BÀI TỐN


1.4. KẾT CHƯƠNG
Chương này trình bày ....



CHƯƠNG 2:

PHÂN TÍCH THIẾT KẾ HỆ THỐNG

Chương này trình bày về phân tích và triển khai hệ thống, bao gồm phân tích
hiện trạng, phân tích u cầu của bài tốn. Phần tiếp theo trình bày các nội dung
thiết kế hệ thống bao gồm ....
2.1. PHÂN TÍCH HIỆN TRẠNG
2.2. PHÂN TÍCH U CẦU

Hình 2.1 xxx

2.3. PHÂN TÍCH CHỨC
NĂNG
2.3.1. Đối tượng sử dụng
Đối tượng sẽ sử dụng trang web s

2.3.2. Công nghệ sử dụng:

2.4. TỔ CHỨC CHƯƠNG TRÌNH
2.4.1. Tổ chức thư mục
2.4.2. Tập tin 01
2.4.3. Tập tin 02



2.4.4. Tập tin 03
2.5. KẾT CHƯƠNG
Chương này trình bày ....


CHƯƠNG 3:

TRIỂN KHAI VÀ ĐÁNH GIÁ KẾT QUẢ

Chương này trình bày về kết quả triển khai hệ thống, cấu hình hệ thống và
các thành phần chức năng. Kết quả được đánh giá thông qua các kịch bản thực
nghiệm khác nhau nhằm thể hiện các ưu/nhược của giải pháp đề xuất.
3.1. MƠ HÌNH TRIỂN KHAI
3.1.1. Mơ hình triển khai
3.1.2. Cấu hình hệ thống:
3.1.2.1. Chức năng bán sản phẩm:
Để tạo dựng được Marketplace thì chúng tơi cần 2 thứ cơ bản đó là người giao dịch
và sản phẩm giao dịch. Chúng tôi có tính năng đầu tiên, đó là tạo sản phẩm, tính năng này
sẽ cho phép người tạo một mặt hàng của mình để bán trên thị trường. Để làm được điều đó,
chúng tơi cần tạo mơ hình product với cấu trúc như sau:
struct Product
{ uint id;
string name;
uint price;
address owner;
bool
purchased;
}
Solidity cho phép bạn tạo cấu trúc dữ liệu của riêng mình, với bất kỳ thuộc tính tùy

ý nào. chúng tơi đã làm bằng cách tạo một cấu trúc Product. Nó lưu trữ tất cả các thuộc
tính của Product cần như id, name, price, owner, và purchased.
Chúng tôi tạo một hàm để tạo sản phẩm mới để thực hiện một số việc:
● Tạo một sản phẩm mới với một cấu trúc
● Thêm cấu trúc vào ánh xạ và lưu trữ trên chuỗi khối
● Kích hoạt sự kiện cho ai đó biết sản phẩm đã được tạo


function createProduct(string memory _name, uint _price) public {
// Require a valid name
require(bytes(_name).length >
0);
// Require a valid
price require(_price >
0);
// Increment product


// Create the product
products[productCount] = Product(productCount, _name, _price, msg.sender, false);
// Trigger an event
emit ProductCreated(productCount, _name, _price, msg.sender, false);
}

event
ProductCreated( ui
nt id,
string name,
uint price,
address owner,

bool
purchased
Chúng tôi thêm định nghĩa sự kiện để nó có thể được kích hoạt:
Những người khác có thể lắng nghe sự kiện này để xác minh rằng một sản phẩm đã
được tạo trên chuỗi khối.
3.1.2.2. Chức năng mua sản phẩm:
Ngồi chức năng tạo và bán sản phẩm thì chúng tơi cũng có chức năng mua sản
phẩm từ người khác với các thao tác đơn giản.


function purchaseProduct(uint _id) public payable {
// Fetch the product
Product memory _product = products[_id];
// Fetch the owner
address payable _seller = _product.owner;
// Make sure the product has a valid id
require(_product.id > 0 && _product.id <= productCount);
// Require that there is enough Ether in the
transaction require(msg.value >= _product.price);
// Require that the product has not been purchased
already require(!_product.purchased);
// Require that the buyer is not the
seller require(_seller != msg.sender);
// Transfer ownership to the buyer
_product.owner = msg.sender;
// Mark as purchased
_product.purchased = true;
// Update the product
products[_id] =
_product;

// Pay the seller by sending them Ether
Chúng tôi sẽ thiết lập chức năng để làm điều này như sau:


address(_seller).transfer(msg.value);
// Trigger an event
emit ProductPurchased(productCount, _product.name, _product.price, msg.sender,
true);
}
Chúng tôi đã làm cho chức năng này phải trả tiền, có nghĩa là nó sẽ chấp nhận tiền
điện tử Ethereum. Bởi vì chúng tôi muốn trả tiền cho chủ sở hữu, chúng tơi phải xây dựng
cấu trúc và sự kiện hiện có để sử dụng loại địa chỉ phải trả như thế này:
struct Product
{ uint id;
string name;
uint price;
address payable
owner; bool
purchased;
}
event
ProductCreated( ui
nt id,
string
name, uint
price,
address payable
Chúng tôi cần tạo một sự kiện mới để bán sản phẩm. Nó sẽ hoạt động gần giống
như sự kiện tạo mới Product mà chúng ta đã tạo ở mục 3.2, ta sẽ có như sau:
event

ProductPurchased( ui
nt id,
string
name, uint
price,
address payable
owner, bool purchased
3.1.2.3.

Xây dựng trang web Marketplace: (Frontend)

3.1.2.3.1. Kết nối với ví Metamask:
Tạo một giao diện card để hiển thị các thơng tin khi kết nối với ví Metamask gồm 2
thơng tin: Địa chỉ (Address) và số dư của ví (Balance).
Chúng tôi tạo hàm connectWalletHandler để kết nối với Wei của ví Metamask như


const connectWalletHandler = () => {
if (window.ethereum && window.ethereum.isMetaMask) {
window.ethereum.request({ method: 'eth_requestAccounts'})
sau:


.then(result => {
accountChangedHandler(result[0]);
setConnButtonText('Wallet Connected');
getAccountBalance(result[0]);
})
.catch(error => {
setErrorMessage(error.message);

});
} else {
console.log('Need to install MetaMask');
setErrorMessage('Please install MetaMask browser extension to
interact');
}
}
Chúng tôi xây dựng thêm các hàm cập nhật địa chỉ và số dư tài khoản mặc định để
nó hiển thị ở Address và Balance. Kết quả sẽ trả về cho hàm accountChangedHandler:
// update account, will cause component re-render
const accountChangedHandler = (newAccount) =>
{
setDefaultAccount(newAccount);
getAccountBalance(newAccount.toString());
}
const getAccountBalance = (account) => {
window.ethereum.request({method: 'eth_getBalance', params:
[account,
'latest']})
.then(balance => {
setUserBalance(ethers.utils.formatEther(balance));
})
.catch(error => {
setErrorMessage(error.message);
});
Tuy nhiên khi thay đổi tài khoản trên ví Metamask thì dữ liệu không thể tự thay đổi
sang tài khoản mới nên chúng tơi đã thêm một số lệnh để có sự thay đổi trên ví thì các
thơng tin trong card sẽ tự update lại.
const chainChangedHandler = () => {
// reload the page to avoid any errors with chain change mid use of

application
window.location.reload();
}
// listen for account changes
window.ethereum.on('accountsChanged', accountChangedHandler);
window.ethereum.on('chainChanged', chainChangedHandler);


Cuối cùng là return để hiển thị toàn bộ giao diện của card:
return (


<div className='walletCard'>

{"Connection to MetaMask"}


onClick={connectWalletHandler}>{connButtonText}</Button>
<div className='accountDisplay'>

Address: {defaultAccount}


</div>
<div className='balanceDisplay'>

Balance: {userBalance}


</div>
{errorMessage}
</div>
);
3.1.2.3.2. Giao diện tạo sản phẩm:
Chúng tôi tạo một hàm mới sẽ được gọi bất cứ khi nào thành phần React của chúng
ta được tải. Bên trong đây, chúng ta sẽ gọi một hàm khởi tạo web3. Và tạo hàm
loadWeb3() sẽ tạo kết nối như thế này:
async componentWillMount()

{ await this.loadWeb3()
}
async loadWeb3() {
if (window.ethereum) {
window.web3 = new Web3(window.ethereum)
await window.ethereum.enable()
}
else if (window.web3) {
window.web3 = new Web3(window.web3.currentProvider)
}
else {
window.alert('Non-Ethereum browser detected. You should consider trying
MetaMask!')
}
}
Chúng tôi tạo một chức năng tải dữ liệu từ chuỗi khối. Chúng tơi sẽ gọi nó đầu tiên
như thế này:
async componentWillMount()
{ await this.loadWeb3()
await this.loadBlockchainData()
}
Chúng tôi đã kết nối đã lưu kết nối web3 vào một biến. Bây giờ, hãy tìm nạp các tài
khoản từ Metamask và đăng nhập chúng vào bảng điều khiển như sau:


async loadBlockchainData() {
const web3 =
window.web3



// Load account
const accounts = await
web3.eth.getAccounts() this.setState({
account: accounts[0] })
const networkId = await web3.eth.net.getId()
const networkData =
Marketplace.networks[networkId] if(networkData) {
const marketplace = web3.eth.Contract(Marketplace.abi, networkData.address)
console.log(marketplace)
} else {
window.alert('Marketplace contract not deployed to detected network.')
}
Ở đây, chúng tôi đã kết nối với Metamask, tức là Ganache. Chúng tôi sẽ sử dụng ID
mạng này để kết nối với hợp đồng thông minh được triển khai trên mạng Ganache, thay vì
mạng Ethereum chính chẳng hạn. Tiếp theo, chúng tôi khởi tạo hợp đồng thông minh với
Web3.js bằng web3.eth.Contract(). Chúng tôi cần 2 thông tin để thực hiện việc này: hợp
đồng thông minh ABI và địa chỉ. Chúng tôi tìm nạp cả hai thứ đó từ tệp mà chúng tơi vừa
nhập. Cuối cùng, nếu chúng tơi khơng thể tìm thấy hợp đồng thông minh trên mạng, chúng
tôi sẽ thông báo cho người dùng. Bạn có thể kiểm tra điều này bằng cách chuyển sang
mạng Ethereum chính trong Metamask (đừng quên chuyển ngược lại).


Ta để hiển thị ra giao diện cuối cùng thì:
purchaseProduct(id, price) {
this.setState({ loading: true
})
this.state.marketplace.methods.purchaseProduct(id).send({ from: this.state.account,
value: price })
.once('receipt', (receipt) => {
this.setState({ loading: false

})
})
}
render() {
return (
<div>
<Navbar account={this.state.account} />
<div className="container-fluid mt-5">
<div className="row">
<main role="main" className="col-lg-12">
{ this.state.loading
? <div id="loader" className="text-center mt-5">

Loading...


<Button onClick={() => window.location.reload(false)}>Click to reload!
</Button>
</div>
:

products={this.state.products}
createProduct={this.createProduct}
purchaseProduct={this.purchaseProduct}
/>
}
</main>
</div>
</div>
</div>
);
}

3.1.2.3.3. Giao diện danh sách các sản phẩm:
Chúng tôi tạo một cách để bán sản phẩm từ trang web Marketplace. Chúng tôi sẽ
thực hiện các nhiệm vụ sau:
● Tạo một thành phần phản ứng giữ giàn giáo cho mã của chúng tôi, bao gồm một
biểu mẫu cho phép người dùng liệt kê các sản phẩm mới, một bảng hiển thị các sản
phẩm để bán và một bảng khác để hiển thị các sản phẩm thuộc sở hữu của mình.
● Chúng tôi sẽ kết nối biểu mẫu để người dùng thực sự có thể liệt kê sản phẩm của
họ để bán trên chuỗi khối.
Để thực hiện được thì chúng tơi cần thêm một số dữ liệu khác vào hàm
loadBlockchainData() của chúng tôi.
Đầu tiên, chúng tôi tạo một hàm JavaScript chấp nhận các tham số giống như chức
năng hợp đồng thông minh của chúng tơi. Sau đó, trước khi gọi chức năng hợp đồng thơng
minh, chúng tơi nói với React rằng ứng dụng của chúng tôi đang "Loading" để người dùng
biết rằng chức năng đã được gửi. Sau đó, chúng tơi gọi chức năng hợp đồng thông minh
với Web3.js với this.state.marketplace.methods.createProduct(name, price).send({ from:
this.state.account }). Thao tác này gọi hàm và cho Web3 biết rằng tài khoản hiện tại là
người dùng đang gọi nó. Cuối cùng, khi đã nhận được biên lai giao dịch, chúng tơi xóa ứng
dụng khỏi trạng thái "đang tải" để người dùng biết lệnh gọi hàm đã hoàn tất.


async loadBlockchainData() {
const web3 = window.web3
// Load account
const accounts = await
web3.eth.getAccounts() this.setState({
account: accounts[0] })
const networkId = await web3.eth.net.getId()
const networkData =
Marketplace.networks[networkId] if(networkData) {
const marketplace = web3.eth.Contract(Marketplace.abi, networkData.address)

this.setState({ marketplace })
const productCount = await marketplace.methods.productCount().call()
console.log(productCount.toString())
this.setState({ loading: false})


} else {
window.alert('Marketplace contract not deployed to detected network.')
}
}
Tạo một chức năng thêm sản phẩm vào chuỗi khối bằng cách gọi hàm
createProduct() với Web3.js và chúng tơt liên kết nó với thành phần bên trong hàm tạo như
sau:
createProduct(name, price) {
this.setState({ loading: true
})
this.state.marketplace.methods.createProduct(name, price).send({
from: this.state.account })
.once('receipt', (receipt) => {
this.setState({ loading: false
})
})
constructor(props) {
// ...
this.createProduct = this.createProduct.bind(this)
Thành phần này bổ sung khung cho giao diện người dùng Marketplace. Nó cũng
tạo ra một biểu mẫu sẽ thêm sản phẩm vào chuỗi khối bằng cách gọi hàm createProduct().


render() {

return
(
<div id="content" style={{marginTop: '15px'}}>
<Row className='text-center'>
style={{ marginLeft: '15px', marginRight: '4rem'
}} className="col mb-2 text-center"
>
<WalletCard/>
</Card>
<div className="col mb-2">

Add Product


<Form onSubmit={(event) => {
event.preventDefault()
const name = this.productName.value
const price = window.web3.utils.toWei(this.productPrice.value.toString(),
'Ether')
this.props.createProduct(name, price)
}}>
<div className="form-group mr-sm-2">
id="productName"
type="text"
ref={(input) => { this.productName = input
}} className="form-control"


placeholder="Product Name"
required />
</div>

<InputGroup className="form-group mr-sm-2 mb-2">
id="productPrice"
type="text"
ref={(input) => { this.productPrice = input }}
className="form-control"
placeholder="Product Price"
required
/>
<InputGroup.Text>Ether</InputGroup.Text>
</InputGroup>
<button type="submit" className="btn btn-primary">Add Product</button>
</Form>

 


</div>
</Row>
<div style={{marginTop: '15px'}}>

Buy Product


striped bordered hover
variant="dark">
<thead>
<tr>
<th scope="col">#</th>
<th scope="col">Name</th>
<th scope="col">Price</th>
<th scope="col">Owner</th>
<th scope="col">Buy</th>
</tr>
</thead>

<tbody id="productList">
{ this.props.products.map((product, key) => {
if(!(product.owner === this.props.account)){
return(
<tr key={key}>
<th scope="row">{product.id.toString()}</th>
<td>{product.name}</td>
<td>{window.web3.utils.fromWei(product.price.toString(), 'Ether')}
Eth</td>
<td>{product.owner}</td>
<td>
name={product.id}
value={product.price}
onClick={(event) => {
this.props.purchaseProduct(event.target.name, event.target.value)


×