Solidity 是以太坊官方支持的用于编写智能合约的语言,在语法上参考了 JavaScript 和 Java 等语言,语法和概念上基本类似。
本次实验参考了
进行了一个简单的实验和学习,cryptozombies是一款使用了区块链技术开发的DAPP,其主要是一个建立自己的僵尸军团进行拓展和升级的游戏。本次实验我参考教程,完成简单的实现。
游戏的主要文件结构如下:
各个文件作用的介绍:
- Zombiefactory.sol本智能合约主要包含僵尸的基本结构、创建僵尸、创建随机僵尸、生成随机僵尸的方法。
- Zombiefeeding.sol 本智能合约主要包含僵尸的互食以及产生新的僵尸
- Zombieattack.sol 本智能合约实现了两个僵尸在战斗的时候的一些过程和逻辑
- Zombiehelper.sol本智能合约实现了设置僵尸的升级花费,以及修改僵尸的一些信息时需要的必要条件
- Zombieownership.sol本智能合约实现了僵尸的所有者转换以及收益,
- Erc721.sol 代币交易相关的接口
- Ownable.sol 控制执行的权限问题
- Safemath.sol 为溢出问题提供解决方案
- Index.html一个简单的web3和智能合约交互的界面
下面是每个和约具体的代码实现:
Zombiefactory.sol代码实现:
在本合约中
pragma solidity >=0.5.0 <0.6.0;
pragma 表示 Solidity 的版本号,这个合约的版本需要在 0.5.0 和 0.6.0 之间。
import "./ownable.sol";
import "./safemath.sol";
使用 import 语句引入其他 Solidity 文件,其中包括 Ownable 合约和 SafeMath 合约。Ownable 合约定义了一个基本的权限控制系统,而 SafeMath 合约提供了数学计算函数,用于防止整数溢出等问题。
権限制御システムを使用するために Ownable コントラクトを拡張する ZombieFactory というコントラクトを定義します。SafeMath のライブラリ関数は、数学的計算中の整数オーバーフローなどの問題を回避するために使用されます。新しいゾンビが作成されたときにログに記録して通知するイベントを定義します。
DNA ビット、DNA 弾性率、クールダウン時間を含む、多数の定数が定義されています。
ゾンビのプロパティを表すために、Zombie という構造体を定義します。
Zombie[] パブリック ゾンビ: すべてのゾンビを格納するための動的配列を定義します。
マッピング (uint => アドレス) publicゾンビToOwner;
マッピング (アドレス => uint) ownerZombieCount;
ゾンビの所有者と各所有者が持つゾンビの数を保存するための 2 つのマップを定義します。
新しいゾンビを作成する _createZombie という内部関数を定義します。この関数は、新しいゾンビをゾンビ配列に追加し、その所有者を現在のメッセージの送信者として設定し、この所有者が所有するゾンビの数を増やします。最後に、この関数は NewZombie イベントを起動して、新しいゾンビが作成されたことを外部に通知します。
DNA シーケンスをランダムに生成するための _generateRandomDna というプライベート関数を定義します。
createRandomZombie という関数を定義して、ランダムに生成された DNA シーケンスから新しいゾンビを作成します。
Zombiefeeding.sol のコードは次のとおりです。
このスマート コントラクトには、以前に定義された ZombieFactory コントラクトを継承する ZombieFeeding と呼ばれるコントラクトが含まれています。
KittyInterface と呼ばれるインターフェイスは、外部コントラクトと対話するために定義されています。このインターフェースには、キティに関連する情報を返すために使用される関数 getKitty があり、特別なタイプのゾンビを設定するときにさまざまな属性を取得するために使用されます。
OnlyOwnerOf という名前の修飾子が宣言されています。これには、呼び出し元が _zombieId が属するゾンビの所有者である必要があります。そうでない場合、関数は例外をスローします。
setKittyContractAddress函数用于将 kittyContract 变量设置为指定地址 _address 所对应的 KittyInterface 类型的合约实例。由于该函数使用了 onlyOwner 修饰符,因此只有合约所有者才能调用该函数。
_triggerCooldown函数用于在喂养僵尸之后,将僵尸的冷却时间重置为 cooldownTime。它接受一个名为 _zombie 的存储类型的参数,该僵尸的冷却时间将被修改。
_isReady函数用于检查僵尸是否已经完成冷却,它接受一个名为 _zombie 的存储类型的参数,并返回一个布尔值。
feedAndMultiply 函数接收Zombie ID、目标 DNA 和种类字符串作为参数。首先,它检查给定 Zombie 是否已经准备好进行交配(即其 readyTime 是否已过)。然后它从给定的目标 DNA 中提取出 DNA 模数,并将其与给定 Zombie 的 DNA 相加取平均数以生成新的 DNA。如果给定的种类字符串等于 "kitty",则将新的 DNA 设为除以 100 的余数加上 99。最后,使用 _createZombie 函数创建一个名为 "NoName" 的新 Zombie,并将其 DNA 设为新生成的 DNA,然后调用 _triggerCooldown 函数将给定 Zombie 的 readyTime 设为当前时间加上 cooldownTime。
feedOnKitty 函数接收Zombie ID 和猫的 ID 作为参数,调用 KittyContract 的 getKitty 函数以获取猫的 DNA,然后调用 feedAndMultiply 函数以将给定 Zombie 的 DNA 和猫的 DNA 相加取平均数以生成新的 DNA,并创建一个新的 Zombie。这个函数可以公开访问,因此任何人都可以使用它来喂养他们的 Zombie。
Zombieattack.sol 的代码如下:
このスマート コントラクトは、ゾンビ攻撃と呼ばれる、ゾンビとの相互攻撃のプロセスを処理するために使用されるスマート コントラクトを実装します。
このコントラクトは ZombieHelper コントラクトをインポートします。これは、ZombieHelper コントラクトで定義されたすべての関数と変数が含まれていることを意味します。
randNonce は、乱数を生成するために使用されるシードです。
AttackVictoryProbability は攻撃勝利の確率で、70% に初期化されます。
randMod は、乱数を生成し、それを特定の範囲に制限するために使用される内部関数です。この関数は、現在時刻、呼び出し元のアドレス、および randNonce 値を連結し、keccak256 ハッシュ アルゴリズムを通じてハッシュ値を計算し、数値に変換します。最後に、この数値は指定された引数を法として取得され、0 から (_modulus - 1) までの数値が返されます。
攻撃関数は、まず攻撃者と攻撃される側のゾンビ情報を取得し、randMod関数を使って乱数を生成し、その乱数が AttackVictoryProbability 以下であれば攻撃者の勝ちとなります。この場合、攻撃側の勝利数とレベルが増加し、攻撃された側の敗北数が増加し、feedAndMultiply 関数が呼び出されて、攻撃側の DNA と攻撃側の DNA を混合して、新しいゾンビ。攻撃者が負けた場合、攻撃者の敗北数と攻撃された側の勝利数をインクリメントし、_triggerCooldown 関数を呼び出して、ゾンビのクールダウン タイマーを再起動します。
Zombiehelper.sol コードは次のとおりです。
このスマートコントラクトは、ゾンビのアップグレードコストの設定とゾンビの一部の情報の変更に必要な条件を実装します。
AboveLevel という名前のデコレーターを定義します。デコレーターでは、装飾された関数の 2 番目のパラメーター (_zombieId) に対応するゾンビのレベルが最初のパラメーター (_level) 以上である必要があります。そうでない場合は、例外がスローされ、関数が実行されます。止められます。
引き出し関数は、契約所有者のみが呼び出せるように変更され、現在の契約アドレスからすべての残高を契約所有者に送信します。
setLevelUpFee の関数は、契約所有者のみが呼び出せるように変更され、levelUpFee の値は渡されたパラメーターで設定されます。
levelUp函数只能由外部调用,并且调用者必须支付一个等于levelUpFee的以太币,否则会抛出异常并停止函数执行。如果满足条件,则增加指定僵尸的等级。
changeName函数只能由外部调用,并要求满足以下条件:指定的僵尸的等级大于等于2,调用者必须是该僵尸的所有者。如果满足条件,则将指定僵尸的名称更改为新的名称。
changeDna函数只能由外部调用,并要求满足以下条件:指定的僵尸的等级大于等于20,调用者必须是该僵尸的所有者。如果满足条件,则将指定僵尸的DNA更改为新的DNA。
getZombiesByOwner的函数它只能由外部调用,并返回指定所有者所拥有的所有僵尸的ID。它首先创建了一个动态数组result,其长度等于指定所有者所拥有的僵尸数量,然后循环遍历所有的僵尸,如果某个僵尸的所有者是指定的所有者,则将该僵尸的ID添加到result中,最终返回result数组。
Zombieownership.sol的代码如下:
本智能合约实现名为ZombieOwnership的智能合约,它是从从ZombieAttack和ERC721继承而来的。它实现了ERC721标准中定义的接口,用于管理和交易Zombie。
balanceOf(address _owner)函数返回指定地址所有拥有的令牌数量。
ownerOf(uint256 _tokenId)函数返回拥有指定令牌的地址。
_transfer(address _from, address _to, uint256 _tokenId)执行令牌的所有权转移。
transferFrom(address _from, address _to, uint256 _tokenId):用于授权地址将指定的令牌转移到另一个地址。
approve(address _approved, uint256 _tokenId):用于授权地址对指定的令牌进行管理。
Erc721.sol 代码:
本合约定义了RC721,erc721是Ethereum上的一种代币标准,它定义了一种可互换的非同质代币(NFT)协议,允许用户拥有并交易不同的代币,每个代币都是独一无二的。
该合约定义了以下四个函数:
balanceOf(address _owner)函数返回指定地址所拥有的代币数量。
ownerOf(uint256 _tokenId)函数返回指定代币ID的所有者地址。
transferFrom(address _from, address _to, uint256 _tokenId)函数从一个地址向另一个地址转移指定代币ID的所有权。
approve(address _approved, uint256 _tokenId)函数将代币ID的所有权授权给另一个地址,以便该地址可以转移代币。
Ownable.sol 代码如下:
本智能合约包含一个名为 Ownable 的智能合约,Ownable 智能合约提供了一种方便的方式,用于控制谁可以执行合约中的敏感操作,例如修改合约的状态或者提取合约中的资产。通常情况下,只有合约的所有者才有权限执行这些操作,而其他用户只能执行只读操作。通过继承 Ownable 智能合约,其他合约可以获得类似的权限控制功能,从而确保合约中的操作都得到了适当的授权和认证。
私有变量 _owner:表示合约的所有者地址。
OwnershipTransferred 事件:用于在所有者发生变化时触发通知。
构造函数将合约的创建者设置为所有者,并触发 OwnershipTransferred 事件,通知合约已经被创建。
公共函数 owner(),用于获取合约的所有者地址。
修饰符 onlyOwner(),用于限制只有合约的所有者才能调用某些函数。
公共函数 isOwner(),用于判断当前调用者是否是合约的所有者。
パブリック関数 renounceOwnership()。コントラクトの所有者のみがこの関数を呼び出して、コントラクトの所有権を放棄し、OwnershipTransferred イベントをトリガーし、_owner を address(0) に設定できます。
パブリック関数 transferOwnership(address newOwner) は、コントラクトの所有者のみがこの関数を呼び出してコントラクトの所有権を新しい所有者に譲渡し、_transferOwnership() を呼び出して譲渡を実現できます。
内部関数 _transferOwnership(address newOwner) は、コントラクトの所有権を新しい所有者に譲渡し、OwnershipTransferred イベントをトリガーし、_owner 変数の値を更新するために使用されます。所有権を譲渡する前に、新しい所有者のアドレスが 0 でないことを確認する必要があります。
Safemath.sol コードは次のとおりです。
このスマート コントラクトは、アサートと関連する解釈を組み合わせて、uint 型データのオーバーフロー セキュリティ問題に対する解決策を提供します。