این مقاله بر اساس این پست در مدیوم نوشته شده توسط مانوئل آرائوز پیش خواهد رفت.
اثبات وجود چیست؟
اثبات وجود سرویسی است که وجود سند یا پرونده را در یک زمان خاص از طریق تراکنش های دارای مهر زمان تأیید می کند. PoE از ماهیت یک طرفه توابع هش رمزنگاری برای کاهش میزان اطلاعاتی که باید در بلاک چین ذخیره شود ، استفاده می کند.
در این مقاله ، ما قصد داریم با ایجاد اثبات ساده قرارداد وجود و تعامل با آن در بلاک چین، بهترین شیوه های اولیه توسعه قرارداد هوشمند اتریوم را معرفی کنیم.
محیط را تنظیم کنید
به بلاک چین متصل شوید
در این مقاله ما از رابط خط فرمان Ganache ، ganache-cli استفاده خواهیم کرد.
می توانید ganache-cli را با دستور زیر نصب کنید:
s
udo npm install -g ganache -cli
و با نوشتن ganache-cli در کنسول. این بلاکچین را راه اندازی کنید.
ganache-cli
وقتی ganache-cli اجرا می شود، می بینید که با 10 حساب شروع می شود. هر یک از این حساب ها با اتر شارژ شده است، بنابراین ما نیازی به استخراج یا بدست آوردن اتر نداریم.
Ganache-cli یک بلاک چین توسعه را راه اندازی می کند که باید در حین توسعه برنامه اجرا شود ، بنابراین تا زمانی که به کار بر روی برنامه ادامه می دهیم ، آن را اجرا کنید.
چارچوب توسعه ترافل
Solidity محبوب ترین زبان برنامه نویسی برای نوشتن قراردادهای هوشمند در اتریوم است. ما در طول این دوره از Solidity استفاده خواهیم کرد.
چارچوب توسعه ترافل یکی از محبوب ترین ابزارهای توسعه برای نوشتن قراردادهای هوشمند Solidity برای اتریوم است. ترافل به ما کمک می کند تا قراردادهای هوشمند خود را پس از نوشتن؛ کامپایل، دپلوی و تست کنیم.
برای نصب ترافل
$ sudo npm install -g truffle
$ sudo npm install -g @truffle/hdwallet-provider
یک فهرست پروژه ایجاد کنید و ترافل را راه اندازی کنید
$ mkdir proof-of-existence
$ cd proof-of-existence/
$ truffle init
ترافل یک دایرکتوری قراردادها تنظیم می کند که در آن ما قراردادهای خود را می نویسیم ، یک فهرست migrate که در آن اسکریپت هایی را برای توسعه قراردادها می نویسیم و یک دایرکتوری آزمایشی که در آن تست هایی را می نویسیم تا مطمئن شویم که قراردادهای ما مطابق انتظار کار می کنند.
در truffle-config.js ما باید شبکه مورد استفاده خود را مشخص کنیم.
در شی module.exports اطلاعات زیر را اضافه کنید:
module.exports = {
networks: {
development: {
host: 'localhost',
port: 8545,
network_id: '*'
}
}
};
ما از این اطلاعات استفاده می کنیم زیرا ganache-cli بلاک چین توسعه ما را روی localhost: 8545 اجرا می کند و این همان چیزی است که ما می خواهیم به آن متصل شویم. تعیین network_id بعنوان * بدین معناست که هر ترافل در هر شبکه ای که در localhost اجرا می شود قرار می گیرد: 8545.
Truffle با یک قرارداد Migrations.sol همراه است که Migrationهای ما و همچنین یک اسکریپت 1_initial_migrations.js را برای Deploy قرارداد Migrations.sol نگه می دارد.
دستور زیر را در ترمینال موجود در فهرست پروژه خود اجرا کنید:
$ truffle migrate
ترمینال باید اطلاعات مربوط به deploy قرارداد migrate را چاپ کند.
این بدان معنی است که محیط شما به درستی تنظیم شده است و ما می توانیم به نوشتن قراردادهای هوشمند خود ادامه دهیم.
نوشتن قرارداد هوشمند Ethereum
$ truffle create contract ProofOfExistence1
اکنون قرارداد ProofOfExistence1.sol را در ویرایشگر متن مورد علاقه خود باز کنید، و این نسخه اولیه کد را جای گذاری کنید:
pragma solidity ^0.5.0;
contract ProofOfExistence1 {
// state
bytes32 public proof;
// calculate and store the proof for a document
// *transactional function*
function notarize(string memory document) public {
proof = proofFor(document);
}
// helper function to get a document's sha256
// *read-only function*
function proofFor(string memory document) public pure returns (bytes32) {
return sha256(abi.encodePacked(document));
}
}
بیایید ProofOfExistence1 را در شبکه مستقر کنیم! این بار باید فایل migration (migrations / 2_deploy_contracts.js) را ویرایش کنید تا Truffle قرارداد جدید ما را مستقر کند. مطالب را با موارد زیر جایگزین کنید:
var ProofOfExistence1 = artifacts.require("./ProofOfExistence1.sol");
module.exports = function(deployer) {
deployer.deploy(ProofOfExistence1);
};
برای اجرای مجدد این انتقال ، باید از flag تنظیم مجدد استفاده کنید تا مطمئن شوید دوباره اجرا می شود.
$ truffle migrate --reset
تعامل با قرارداد هوشمند
$ truffle console
حالا باید در ترمینال چنین چیزی ببینید:
truffle(development)>
در خط اول این دستور را وارد کنید:
var poe = await ProofOfExistence1.at(ProofOfExistence1.address)
این خط می گوید که متغیر “poe” نمونه ای از ProofOfExistence1.sol است که در آدرسی که ما به تازگی deploy کرده ایم یافت می شود.
با وارد کردن این دستور می توانید آدرس را مشاهده کنید:
truffle(development)> poe.address
'0xc490df1850010ea8146c1dd3e961fedbf6b85bef'
برای فراخوانی تابع notarize، ما آن را مانند سایر توابع جاوا اسکریپت فراخوانی می کنیم.
truffle(development)> poe.notarize('Hello World!')
{ tx: '0x60ae...2643cbea65',
receipt: …
}
این تابع باعث تغییر state می شود، بنابراین یک تابع شامل تراکنش است.
ما می توانیم با این دستور اثبات وجود این متن را چک کنیم:
truffle(development)> poe.proofFor('Hello World!')
‘0x7f83b...126d9069’
و بررسی کنید که state قرارداد به درستی تغییر کرده باشد:
truffle(development)> poe.proof()
'0x7f83b...126d9069'
هش ها مطابقت دارند!
// get the deployed version of our contract
truffle(default)> var poe = ProofOfExistence1.at(ProofOfExistence1.address)
// and print its address
truffle(default)> poe.address
0x3d3bce79cccc331e9e095e8985def13651a86004
// let's register our first "document"
truffle(default)> poe.notarize('An amazing idea')
{ tx: '0x18ac...cb1a',
receipt:
{ transactionHash: '0x18ac...cb1a',
...
},
logs: [] }
// let's now get the proof for that document
truffle(default)> poe.proofFor('An amazing idea')
0xa3287ff8d1abde95498962c4e1dd2f50a9f75bd8810bd591a64a387b93580ee7
// To check if the contract's state was correctly changed:
truffle(default)> poe.proof()
0xa3287ff8d1abde95498962c4e1dd2f50a9f75bd8810bd591a64a387b93580ee7
// The hash matches the one we previously calculated
Iterating the contract code
pragma solidity ^0.5.0;
contract ProofOfExistence2 {
// state
bytes32[] private proofs;
// store a proof of existence in the contract state
// *transactional function*
function storeProof(bytes32 proof)
public
{
proofs.push(proof);
}
// calculate and store the proof for a document
// *transactional function*
function notarize(string calldata document)
external
{
bytes32 proof = proofFor(document);
storeProof(proof);
}
// helper function to get a document's sha256
// *read-only function*
function proofFor(string memory document)
pure
public
returns (bytes32)
{
return sha256(abi.encodePacked(document));
}
// check if a document has been notarized
// *read-only function*
function checkDocument(string memory document)
public
view
returns (bool)
{
bytes32 proof = proofFor(document);
return hasProof(proof);
}
// returns true if proof is stored
// *read-only function*
function hasProof(bytes32 proof)
internal
view
returns (bool)
{
for (uint256 i = 0; i < proofs.length; i++) {
if (proofs[i] == proof) {
return true;
}
}
return false;
}
}
// deploy contracts
truffle(default)> migrate --reset
// Get the new version of the contract
truffle(default)> var poe = ProofOfExistence2.at(ProofOfExistence2.address)
// let's check for some new document, and it shouldn't be there.
truffle(default)> poe.checkDocument('hello')
false
// let's now add that document to the proof store
truffle(default)> poe.notarize('hello')
{ tx: '0x1d2d...413f',
receipt: { ... },
logs: []
}
// let's now check again if the document has been notarized!
truffle(default)> poe.checkDocument('hello')
true
// success!
// we can also store other documents and they are recorded too
truffle(default)> poe.notarize('some other document');
truffle(default)> poe.checkDocument('some other document')
true
pragma solidity ^0.5.0;
contract ProofOfExistence3 {
mapping (bytes32 => bool) private proofs;
// store a proof of existence in the contract state
function storeProof(bytes32 proof)
internal
{
proofs[proof] = true;
}
// calculate and store the proof for a document
function notarize(string calldata document)
external
{
bytes32 proof = proofFor(document);
storeProof(proof);
}
// helper function to get a document's sha256
function proofFor(string memory document)
pure
public
returns (bytes32)
{
return keccak256(bytes(document));
}
// check if a document has been notarized
function checkDocument(string memory document)
public
view
returns (bool)
{
bytes32 proof = proofFor(document);
return hasProof(proof);
}
// returns true if proof is stored
function hasProof(bytes32 proof)
internal
view
returns(bool)
{
return proofs[proof];
}
}