实验1 Solidity基础

实验流程

  • 新建文件AnimalIncubators.sol
  • 建立一个基础合约 AnimalIncubators,并指定Solidity编译器版本
  • 创建宠物结构体与所用常量,及公共数组animals[]
  • 依据描述完成_createAnimal、_generateRandomDna、createRandomAnimal三个函数

实验代码

pragma solidity >=0.4.12 <0.6.0;

contract Animallncubators {
uint dnaDigits = 16;
uint dnaLength = 10**16;
struct Animal {
uint dna;
string name;
}
Animal[] public animals;
event NewAnimal(uint AnimalId, string name, uint dna);
function _createAnimal(string _name, uint _dna) private {
animals.push(Animal(_dna, _name));
uint _animalId = animals.length - 1;
NewAnimal(_animalId, _name, _dna);
}
function _generateRandomDna(string _str) private view returns (uint){
uint rand = uint(keccak256(_str));
return rand % dnaLength;
}
function createRandomAnimal(string _name) public {
uint randDna = _generateRandomDna(_name);
_createAnimal(_name, randDna);
}
}

实验效果

如图部署合约后创建三个分别叫Drogon、Rheagal、Viserion的宠物

image-20221013143629630

image-20221013143729922

image-20221013143805379

实验二 Solidity进阶——宠物成长系统

实验流程

  • 创建两个映射 AnimalToOwner、ownerAnimalCount记录宠物拥有者的地址和某地址所拥有宠物的数量。
  • 修改_createAnimal函数来使用映射,得到新宠物后更新映射
  • 修改createRandomAnimal函数,使得每个用户只能调用该函数一次
  • 完成AnimalFeeding合约,增加进食和成长功能: 当一个宠物进食后,它自身的DNA将与食物的DNA结合在一起,形成一个新的宠物DNA

实验代码

AnimalIncubators2.sol

pragma solidity >=0.4.12 <0.6.0;

contract Animallncubators {
uint dnaDigits = 16;
uint dnaLength = 10**16;
struct Animal {
uint dna;
string name;
}
Animal[] public animals;
event NewAnimal(uint AnimalId, string name, uint dna);

mapping(uint=>address) AnimalToOwner;
mapping(address=>uint) ownerAnimalCount;

function _createAnimal(string _name, uint _dna) internal {
animals.push(Animal(_dna, _name));
uint _animalId = animals.length - 1;
AnimalToOwner[_animalId]=msg.sender;
ownerAnimalCount[msg.sender]+=1;
NewAnimal(_animalId, _name, _dna);
}
function _generateRandomDna(string _str) private view returns (uint){
uint rand = uint(keccak256(_str));
return rand % dnaLength;
}

function createRandomAnimal(string _name) public {
require(ownerAnimalCount[msg.sender]==0);

uint randDna = _generateRandomDna(_name);
_createAnimal(_name, randDna);
}
}

AnimalFeeding.sol

pragma solidity >=0.4.12 <0.6.0;
import "./AnimalIncubators2.sol";

contract AnimalFeeding is Animallncubators{
function feedAndGrow(uint _AnimalId,uint _targetDna) internal {
require (keccak256(AnimalToOwner[_AnimalId])==keccak256(msg.sender));
Animal storage myAnimal=animals[_AnimalId];
uint _tDna=_targetDna%dnaDigits;
uint _newDna=uint((myAnimal.dna+_tDna)/2);
_newDna=(_newDna/100)*100+99;
_createAnimal("No-one",_newDna);

}

function _catchFood(uint _name) internal pure returns (uint) {
uint rand = uint(keccak256(_name));
return rand;
}

function feedOnFood(uint _AnimalId,uint _FoodId) public{
uint _FoodDna=_catchFood(_FoodId);
feedAndGrow(_AnimalId,_FoodDna);
}
}

实验效果

首先生成一个宠物

image-20221013152312911

在同一地址下生成第二只宠物报错

image-20221013152412427

在其他地址下生成另外两只宠物image-20221013194828520

给Drogon喂食,产生了No-one

image-20221013153529625

实验三 Solidity高阶理论

实验流程

  • 创建 ownable.sol,并在createRandomAnimal函数中添加onlyOwner
  • 更新宠物结构的属性,新添level readyTime
  • 修改feedAndGrow函数实现冷却效果
  • 完成changeName changeDna getAnimalsByOwner 函数

实验代码

AnimalIncubators3.sol

pragma solidity >=0.4.12 <0.6.0;
import "./ownable.sol";

contract Animallncubators is Ownable {
uint dnaDigits = 16;
uint dnaLength = 10**16;
struct Animal {
uint dna;
string name;
uint32 level;
uint32 readyTime;
}
uint32 cooldownTime = 60;

Animal[] public animals;
event NewAnimal(uint AnimalId, string name, uint dna);

mapping(uint=>address) AnimalToOwner;
mapping(address=>uint) ownerAnimalCount;

function _createAnimal(string _name, uint _dna) internal {
animals.push(Animal(_dna, _name,0,uint32(now)));
uint _animalId = animals.length - 1;
AnimalToOwner[_animalId]=msg.sender;
ownerAnimalCount[msg.sender]+=1;
NewAnimal(_animalId, _name, _dna);
}
function _generateRandomDna(string _str) private view returns (uint){
uint rand = uint(keccak256(_str));
return rand % dnaLength;
}

function createRandomAnimal(string _name) public {
require(ownerAnimalCount[msg.sender]==0);

uint randDna = _generateRandomDna(_name);
_createAnimal(_name, randDna);
}
}

AnimalFeeding.sol

pragma solidity >=0.4.12 <0.6.0;
import "./AnimalIncubators3.sol";

contract AnimalFeeding is Animallncubators{
function feedAndGrow(uint _AnimalId,uint _targetDna) internal {
require (keccak256(AnimalToOwner[_AnimalId])==keccak256(msg.sender));
Animal storage myAnimal=animals[_AnimalId];

require(now>=myAnimal.readyTime);

uint _tDna=_targetDna%dnaDigits;
uint _newDna=uint((myAnimal.dna+_tDna)/2);
_newDna=(_newDna/100)*100+99;
_createAnimal("No-one",_newDna);

myAnimal.readyTime=uint32(now)+cooldownTime;

}

function _catchFood(uint _name) internal pure returns (uint) {
uint rand = uint(keccak256(_name));
return rand;
}

function feedOnFood(uint _AnimalId,uint _FoodId) public{
uint _FoodDna=_catchFood(_FoodId);
feedAndGrow(_AnimalId,_FoodDna);
}
}

AnimalHelper.sol

pragma solidity >=0.4.12 <0.6.0;
import "./AnimalFeeding.sol";

contract AnimalHelper is AnimalFeeding{
modifier aboveLevel (uint _level,uint _AnimalId){
require(animals[_AnimalId].level>=_level);
_;
}

function changeName(uint _AnimalId,string _newName) external aboveLevel(2,_AnimalId){
require(keccak256(msg.sender)==keccak256(AnimalToOwner[_AnimalId]));
animals[_AnimalId].name=_newName;
}

function changeDna(uint _AnimalId,uint _newDna) external aboveLevel(20,_AnimalId){
require(keccak256(msg.sender)==keccak256(AnimalToOwner[_AnimalId]));
animals[_AnimalId].dna=_newDna;
}

function getAnimalsByOwner(address _owner)external view returns(uint[]){
uint [] memory result=new uint[](ownerAnimalCount[_owner]);
uint count=0;
for(uint i=0;i<animals.length;i++){
if(keccak256(AnimalToOwner[i])==keccak256(_owner)){
result[count]=i;
count+=1;
}
}

return result;
}
}

实验效果

onlyOwner

image-20221013155425795

新建一个小动物喂食

image-20221013161950806

再喂一次冷却还没到,报错

image-20221013162023288

再给1号喂

image-20221013162057057image-20221013162057249

这时候总共有0,1,2三只

image-20221013162135266

看一下getAnimalsByOwner函数效果

image-20221013162210136