用Solidity编写智能合约

172 阅读5分钟

什么是智能合约?

由以太坊推广,智能合约是在区块链上存储和执行的程序。这个术语是在90年代末创造的,试图 "为理想的安全提供蓝图"。

这个蓝图规范了事件发生时各方之间的关系,使用代码,使其具有巨大的安全性,并像代码本身一样可预测。

智能合约与外部账户

与外部(以太坊)账户一样,智能合约有地址,可以持有和转移资金。然而,外部账户不受单一网络的约束。你可以用同一个账户连接到任何数量的区块链网络。

另一方面,智能合约只能连接到一个特定的网络。它们可以增强或取代现实生活中的合同,因为它们具有透明性和它们所运行的系统(区块链)的不可更改性。编写这种合同的最流行方式是通过Solidity编程语言。

介绍一下Solidity

Solidity是由Ethereum团队创建的一种编译的面向对象的编程语言,具有类似JavaScript的语法。与JavaScript不同,Solidity是强类型的,并且很好地利用了继承性。

Solidity将我们的源代码编译成可部署的字节码和应用二进制接口(ABI),以便使用其他智能合约或编程语言与字节码互动。

用Solidity写一个智能合约

// SPDX-License-Identifier: UNLICENSED
pragma solidity >=0.4.17 <0.9.0;

contract Storage {
  uint data;

  function set(uint newData) public {
    data = newData;
  }

  function get() public view returns (uint) {
    return data;
  }
}

因为智能合约的源代码通常可以随时阅读,所以最好在第一行指定你的代码的许可证,然后是 [SPDX](https://spdx.org/licenses/)-License-Identifier:.

之后,pragma 指令告诉编译器要使用哪个版本的 Solidity。版本以0. 开始,以表明在小的、定期的更新中会有突破性的变化。我们的智能合约可以针对0.4 或更高的版本进行编译,但不能针对0.9 版本。

契约

Solidity 中的合约与 JavaScript 类非常相似,它们持有可相互作用的变量和方法。但与类不同的是,你不需要this 关键字来访问Solidity中的一个变量。在声明后也必须有分号(函数定义不算)。

我们的Storage 合同持有整数data (由uint 类型关键字注释),并暴露了两个可以改变和显示它的函数。data 变量是一个存储变量,它将在我们合约的有效期内存在。如果我们部署了这个合约,任何人都可以调用setget 来修改和检索data 的值。

在 Solidity 合同中初始化我们的变量

为了用一个值初始化我们的data 变量,合约可以提供一个constructor 函数,该函数需要零或多个参数。

contract Storage {
  uint data;

  constructor (uint defaultData) {
    data = defaultData;
  }

  function set(uint newData) public {
    data = newData;
  }

  function get() public view returns (uint) {
    return data;
  }
}

继承

一个合约可以通过is 关键字从另一个合约继承。

// SPDX-License-Identifier: UNLICENSED
pragma solidity >=0.4.17 <0.9.0;

contract C {
    string public greeting = 'hello';
}

contract D {
    string public farewell = 'goodbye';
}

contract E is C, D {}

合约D 将可以访问greetingfarewell 两个变量。

Solidity 函数

Solidity 函数有以下模式。

function <function name>(<parameters type>) \[function type\] [returns (<return type>)] {}

常用的函数类型是public,external,private,internal,view,pure, 和payable

下面是支配函数可见性的类型是如何工作的。

  • public :任何人都可以调用该函数
  • external: 除了合同之外,任何人都可以调用该函数。使用external ,而不是public ,可以有一个性能提升,并有可能节省大量的气体
  • private :只有持有该函数的合同可以调用它
  • internal :合同及其衍生物可以调用该函数。

这些类型管理对状态的访问。

  • view :该函数只读取状态
  • pure :该函数既不读也不写状态。

请注意,payable 是在函数被调用时可以接受付款时使用的。

一个更详细的函数类型的模式会是这样的。

{public|external|private|internal} [pure|view|payable]

因此,在我们的合同中,具有public view returns (uint) 类型的get 函数是可普遍访问的,读取数据,并返回一个整数。

然而,Solidity 为我们提供了一个捷径,自动创建显示我们状态的get 函数。只需在我们的变量data 前添加关键字public ,一个data 函数就会被创建,以取代我们的get 函数。

contract Storage {
  uint public data; // a data function will be created to access the `data` variable

  constructor (uint defaultData) {
    data = defaultData;
  }

  function set(uint newData) public {
    data = newData;
  }
}

使用Remix进行部署

为了测试和部署我们的合约到区块链网络,我们可以依靠像Remix这样的IDE来简化我们的工作,或者使用一个真正的编码环境。在这篇文章中,我们将使用Remix。

Remix是一个Solidity IDE,用于编译、部署和手动测试Solidity代码。它可以与一系列Ethereum测试网络以及主网络对接。

首先,在contracts 目录下创建一个新的合约,并将我们的合约代码复制过来。

Contracts Directory

Contract Code

当我们的Solidity代码被保存时,Remix会自动编译我们的代码,创建一个被发送到网络的字节码,以及一个ABI来与部署的合约互动。

我们可以在Solidity编译器标签中检查字节码和ABI。

ABI

如果我们的代码编译成功,我们就可以在部署运行事务标签下开始部署和与之交互。

在这个选项卡中,我们可以选择我们的环境、要部署的合约以及要用哪个账户来部署。JavaScript VM ,意味着Remix将在我们的浏览器内维护一个区块链网络,使测试尽可能快地运行。

值输入与payable 函数调用有关,对我们的合约来说是不必要的。

Deployed Contracts

在标签的底部,我们看到Deployed Contracts ,这表明我们可以部署一个或多个合约的多个实例。

Contracts 下,Remix在constructor 函数内拾取了我们的defaultData 。输入一个整数,点击Deploy来部署一个新的合同。

Deploy Dropdown

Storage Dropdown

data 按钮代表我们的public data 变量自动生成的getter,而set 按钮代表我们的set 方法。

颜色上的差异可以归因于这样一个事实,即我们的getterdata 函数并不修改我们应用程序中的状态,因此,在区块链上运行不需要任何成本。然而,我们的set 函数是一个交易类型的函数,它的运行会消耗气体和资源,就像最初的Deploy 按钮。

运行data 函数将返回我们的初始输入2021set 对其进行相应的修改。

Data 2021

Set 2022

Data 2022

结论

在这篇文章中,我们看了Solidity合约的基本构件,以及如何使用Remix IDE编写、编译、部署和测试我们的Solidity代码。从现在开始,我们应该更进一步,使用GanacheTruffle的真实环境。祝你黑客行动愉快。

The postWriting smart contracts with Solidityappeared first onLogRocket Blog.