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
1
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
2
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 1
Đồ á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.
2
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 .... 3
4
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 ....
5
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 count productCount ++; 6
// Create the product products[productCount] = Product(productCount, _name, _price, msg.sender, false); // Trigger an event emit ProductCreated(productCount, _name, _price, msg.sender, false); } Chúng tôi thêm định nghĩa sự kiện để nó có thể được kích hoạt: event ProductCreated( uint id, string name,
uint price, address owner, bool purchased ); 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: Ngoà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. Chúng tôi sẽ thiết lập chức năng để làm điều này như sau: 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
7
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( uint id, string name, uint price, address payable owner, bool purchased ); 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( uint 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ư sau: const connectWalletHandler = () => { if (window.ethereum && window.ethereum.isMetaMask) { window.ethereum.request({ method: 'eth_requestAccounts'}) 8
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> {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 10
Ở đâ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> : account={this.state.account} 11
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}) 12
} 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">
); } Để sử dụng thành phần này thì ta cần khai báo trong App.js và thêm đoạn HTML để thực thi: <main role="main" className="col-lg-12 d-flex"> { this.state.loading ? <div id="loader" className="text-center">
Loading...
</div>
: <Main createProduct={this.createProduct} /> } </main> Chúng tôi cho phép người dùng mua sản phẩm trên thị trường. Chúng ta sẽ làm hai việc trong phần này: ● Liệt kê tất cả các sản phẩm trên trang ● Cho phép người dùng mua sản phẩm được đăng bán chỉ bằng một nút bấm Chúng tôi sử dụng bộ đệm bộ đếm mà chúng tôi đã tạo bên trong hợp đồng thông minh để xác định có bao nhiêu sản phẩm tồn tại, sau đó chúng tơi sử dụng vịng lặp for để tìm nạp từng sản phẩm riêng lẻ và lưu trữ nó vào đối tượng trạng thái phản ứng. Với thông tin này, chúng tơi có thể hiển thị các sản phẩm trên trang trong giây lát. const productCount = await marketplace.methods.productCount().call() this.setState({ productCount }) // Load products for (var i = 1; i <= productCount; i++) { const product = await marketplace.methods.products(i).call() this.setState({ products: [...this.state.products, product] }) } Chúng tôi tạo chức năng mua sản phẩm và liên kết hàm bên trong hàm tạo: 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 }) }) } constructor(props) {
Chúng tôi chuyển hai props mới xuống Main component: ● Tất cả các sản phẩm có thể được liệt kê trên trang ● Hàm buyProduct() để nó có thể được gọi trong thành phần phụ Chúng tơi sẽ cập nhật mã của mình để nó trơng để: ● Lặp lại tất cả các sản phẩm và tạo các hàng bảng duy nhất cho từng sản phẩm ● Thêm một nút để có thể mua sản phẩm chỉ bằng một cú nhấp chuột, gọi hàm buyProduct() mà chúng ta vừa tạo. <main role="main" className="col-lg-12 d-flex"> { this.state.loading ? <div id="loader" className="text-center">
3.2. KẾT QUẢ THỰC NGHIỆM 3.2.1. Khởi động hệ thống Đầu tiên, ta cần khởi động Ganache kích hoạt Workspaces của Marketplace:
17
Sau đó ta chạy lệnh “npm start” để khởi động localhost:3000 hiển thị giao diện của Marketplace.
18
3.2.2. Chức năng kết nối với ví MetaMask
Click vào button Connect Wallet để kết nối:
19
3.2.3. Chức năng tạo mới sản phẩm để bán:
Điền thông tin sản phẩm trong mục Add Product: Product Name: tên của sản phẩm muốn bán Product Price: giá của sản phẩm muốn bán, tính
-
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Ả Qua kết quả thực nghiệm, tác giả có những nhận xét như sau: −
Vấn đề XXX
−
Vấn đề YYY
Thống kê kết quả bằng bảng, đồ thị.... 3.4. KẾT CHƯƠNG Chương này trình bày ....
KẾT LUẬN VÀ HƯỚNG PHÁT TRIỂN 1. KẾT QUẢ ĐẠT ĐƯỢC
Trong thời gian tìm hiểu, nghiên cứu cơ sở lý thuyết và triển khai ứng dụng công nghệ, đồ án đã đạt được những kết quả sau: Về mặt lý thuyết, đồ án đã đạt được … 20
Về mặt thực tiễn ứng dụng, đồ án đã đạt được … Kết quả đóng góp của đồ án được thể hiện như sau (trình bày các đoạn có đánh số ngắn gọn sắp xếp theo mức độ quan trọng giảm dần). Cần làm rõ những nội dung kế thừa, những nội dung mà tác giả đóng góp trong luận văn. −
Phát triển một thuật toán nhanh hơn nhiều cho vấn đề xxx
−
Xây dựng được XYZ. Chứng tỏ được XXX
−
Xác định được YYY
Tuy nhiên, vẫn còn tồn tại các vấn đề như sau: −
Vấn đề XXX
−
Vấn đề YYY
2. KIẾN NGHỊ VÀ HƯỚNG PHÁT TRIỂN
Một số số hướng nghiên cứu và phát triển của đề tài như sau: −
Bổ sung và hoàn thiện một số chức năng của hệ thống …
−
Đánh giá hiệu năng trên các môi trường khác nhau …
−
Kiểm thử các chức năng của chương trình …
−
Bổ sung các giải pháp bảo mật và an toàn cho hệ thống …
−
….
TÀI LIỆU THAM KHẢO Tiếng Việt
[1] Đặng Văn Đức (2001), Hệ thống thông tin địa lý, Nhà xuất bản Khoa học và Kỹ Thuật Hà Nội.
21
[2] Phạm Hữu Đức (2005), Cơ sở dữ liệu và hệ thống thông tin địa lý GIS, Nhà xuất bản Xây dựng. Tiếng Anh
[3] Senthil Shanmugan (2004). “Digital urban management programme Evolution of Bangalore GIS model”, Proceedings of the third International Conference on Environment and Health, India.
[4] Teemu Nuortio, Harri Niska (2003), “Improved route planning and scheduling of waste collection and transport”, Department of Environmental Sciences, University of Kuopio, Finland. Internet