نوشتن یک قرارداد هوشمند (Proof of Existence Exercise)

این مقاله بر اساس این پست در مدیوم نوشته شده توسط مانوئل آرائوز پیش خواهد رفت.

اثبات وجود چیست؟
اثبات وجود سرویسی است که وجود سند یا پرونده را در یک زمان خاص از طریق تراکنش های دارای مهر زمان تأیید می کند. 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];
  }
}
8 پسندیده

سلام وقت بخیر
من نمیدونم منظورتون از (داخل truffle-config.js باد شبکه مورد استفاده رو مشخص کنیم ) چیه
و همینطور ( در شی module.exports )
ممنون میشم راهنماییم کنید

کلا نتونستم تمرینارو انجام بدم و میخوام الان یکی یکی انجام بدم و مشکلامو برطرف کنم

این فایل:
image

شامل این تنطیمات باشه:

module.exports = {
    networks: {
        development: {
            host: 'localhost',
            port: 8545,
            network_id: '*'
        }
    }
};

فقط محض اطلاع: این تمرینیه که تو کلاس انجام دادیم.
تمرین بانک ساده و زنجیره تامبن نمره دارن

vaght b kheyr
ye soal k man manzoor az neveshtane function hashProof ro nafahmidam, aya nemishod dar checkDocument hashProof ra ja dad? aya hadafi az neveshtane in function hast ya kolan dar Solidity adat be joda sazi function ha dar bihstarin hade momken mikonim

ایا در تمرین سوم poe اینطوری نوشته میشد بهتر نبود ؟ یا اینکه اشتباه می شود؟

1 پسندیده

دوست عزیز درسته مشکلی نداره اما توجه کنید مثاله و اگه بخواهید این کانترکت رو توسعه بدید نیازه که ماژولار تر برنامه نویسی کنید که باعث میشه خوانایی کدتون بالا تر بره و تکرار در کد هاتون کمتر میشه

5 پسندیده

سلام
من وقتی می خوام دستور truffle migrate اجرا کنم این خطا رو می گیرم
البتع تو remix قرارداد رو بدون خطا دپلوی کردم. نمی دونم مشکلش چیه
مرسی

1 پسندیده

سلامی دوباره
برای دستور truffle migrate -reset هم همچین خطایی می ده
Screenshot 2022-02-03 190943

1 پسندیده

فکر میکنم داخل فایل truffle-config.js یک کاراکتر در تنظیمات اضافه یا کم گذاشتید چک کنید که کانفیگ شما به صورت زیر باشه

        development: {
            host: "127.0.0.1", // Localhost (default: none)
            port: 8545, // Standard Ethereum port (default: none)
            network_id: "*", // Any network (default: none)
        },
3 پسندیده

سلام
بعد از اجرای دستور truffle migrate این ارور رو به من نشون میده در کامند لاین
میشه لطفا راهنمایی کنید چطور میتونم حلش کنم؟
image

1 پسندیده

داخل فایل truffle-config.js قسمت تنظیمات compilers قسمت solc سپس version رو به ورژن مورد نظر خودتون تغییر بدین مثلا

    compilers: {
        solc: {
            version: "0.5.0", 
        }
    },
4 پسندیده

من توی اجرای truffle init با این ارور مواجه میشم لطفا راهنمایی کنید ممنون
و یه سوال اینکه: من که نمیتونم این ارور هارو خودم رفع کنم ناشی از ضعف من توی کدوم قسمته؟
آیا بیسیک باید چیزی بدونم که دانشش رو ندارم؟ اگر آره لطفا راهنمایی کنید چطور دانشم رو ارتقا بدم که بتونم این تیپ ارور هارو تشخیص بدم و رفع و رجوع کنم مرسی
image

1 پسندیده

نه نیازی نیست همه چیز رو بدونید. مثلا من قبلا با این خطا مواجه نشدم اما با جستجو میتونم دلیل احتمالی رو پیدا کنم و شما رو راهنمایی کنم.
کافیه خطایی که نمایش میده رو جستجو کنید. فقط مثلا اگر کل این خطا رو کپی کنید ممکنه نتیجه نگیرید. چون جزییات مربوط به سیستم شما رو هم داره.
اینجا مشکل اصلی مشخصه loader.js هست که بخاطر پیدا نکردن ماژولیه که آدرسش رو نوشته. من اینو اینطوری سرچ کردم:
دستور + خطا روی فایل + ماژولی که پیدا نمیکنه - آدرس لوکال
truffle init
internal/modules/cjs/loader.js:965
throw err
Cannot find module cli.bundle.js

اولین نتیجه این پیج بود:

و اولین جواب امتیاز بالا داشت پس به احتمال زیاد مشکل شما رو حل میکنه:

اگر حل نشد سراغ جواب بعدی برید. یه نگاهی به جوابا بندازید و با توجه به کارایی که انجام دادید ببینید احتمال کدوم بیشتره. همیشه اولین لینک جواب شمارو نداره یا لزوما خطارو حل نمیکنه. یکی دو پیج اول نتیجه جستجو رو چک کنید.
گاهی لازمه سعی و خطا کنید تا بتونید به جواب برید. همیشه دست به سرچ باشید.

2 پسندیده

ممنون ازینکه وقت گذاشتین
همه ی راه حل هایی که توی اون لینک بود رو تست کردم هیچکدوم جواب نداد
من خودم فکر میکنم از پایین بودن کانفیگ لبتابم باشه
بازم ممنون بابت پاسخگوییتون

1 پسندیده

سلام
اول تشکر کنم از @Mohammadd بابت راهنمایی های که می کنید.
چرا ما تو توابع notarize و checkDocument متغییر proof رو تعریف می کنیم؟ ایا دلیلش اینه که این توابع در memory دارن ذخیره می شن ؟

2 پسندیده

خواهش میکنم دوست عزیز :pray::pray:
متغیر proof داخل memory ذخیره میشه
بیشتر جنبه اینو داره خوانایی کد رو بالا ببره وگرنه میتونید مستقیم هم بنویسید ولی کدتون ناخوانا تر میشه

2 پسندیده

با سلام: من موقع اجرای دستور truffle migrate در همان ابتدای کار با خطا مواجه میشوم که هر چقدر تلاش کردم راه حلی پیدا نکردم ممنون میشم راهنمایی کنید.

1 پسندیده

قدم به قدم از اول پیش برو ، وقتی truffle init و ران میکنی توی vscode چند تا فولدر و فایل ایجاد میشه که یکیش فایل truffle-config.js هستش، برو داخل فایل و اینارو networks: {
development: {
host: ‘localhost’,
port: 8545,
network_id: ‘*’
}
}
}; از کامنت در بیار و حواست باشه port و host با مشخصات ganache-cli یکی باشه

1 پسندیده

باید reset-- بزنید. با دوتا دش

2 پسندیده