你是否曾想过使用Go探索区块链开发?或者想建立由Solana网络驱动的Go应用程序?如果你有,这篇文章就是为你准备的。
区块链是支持加密货币和去中心化应用的技术。它仍处于早期阶段,在一些行业中获得了大规模的采用,导致了新的工作角色和机会。根据ZipRecruiter的数据,区块链开发人员的平均年收入为154,550美元。
开始进行区块链开发的最简单方法是建立一个加密货币钱包,以存储代币和创建交易。现有几个区块链,我最喜欢的一个是Solana,因为它有丰富的生态系统,速度快,而且对开发者友好。
在这篇文章中,我们将学习如何使用Go与Solana网络互动,并建立一个加密货币钱包,从头开始存储、接收和转移硬币。
前提条件
要遵循和理解本教程,你将需要以下条件。
什么是Solana?
Solana($SOL)是全球最快的去中心化区块链,强调速度、可扩展性和用户友好性。它还拥有加密货币领域发展最快的生态系统,有400多个项目,包括Defi、NFTs、Web3等等。
Solana通过提供以下内容从许多其他区块链中脱颖而出。
- 轻松而高效的可扩展性
- 微薄的交易成本(始终低于0.01美元)
- 快速的网络和区块速度(每秒处理高达50,000个交易)
- 抗审查(Solana应用程序将永远自由运行)
一家领先的网络安全公司Kudelski Security已经对Solana的软件架构进行了审计,结果可在此查阅。你也可以在Solana Beach上查看Solana网络的统计数据。
开始使用Go和Solana
安装solana-go-sdk包,这是一个用于Solana的Go软件开发工具包(SDK)。它允许Go应用程序与Solana网络互动,包括使用SolanaJSON RPC API提供的所有方法。
第一步:设置你的开发环境
在你的文本编辑器或IDE中创建一个新的Go项目,并初始化你的go.mod 文件。你可以自由地使用你的软件包的任何名称。
go mod init solana-wallet
第2步:安装Solana SDK for Go
在你的项目中安装solana-go-sdk包。在终端中,输入以下内容。
go get -u github.com/portto/solana-go-sdk
第3步:连接到Solana网络
将Solana SDK包导入你的应用程序中,然后创建一个连接到Solana Mainnet网络的RPC客户端实例。
创建一个名为main.go 的文件,并在其中保存以下代码。
package main
import (
"context"
"fmt"
"github.com/portto/solana-go-sdk/client"
"github.com/portto/solana-go-sdk/client/rpc"
)
func main() {
// create a RPC client
c := client.NewClient(rpc.MainnetRPCEndpoint)
// get the current running Solana version
response, err := c.GetVersion(context.TODO())
if err != nil {
panic(err)
}
fmt.Println("version", response.SolanaCore)
}
在这段代码中,我们将Solana SDK中的client 和client/rpc 模块导入到应用程序中,以创建一个RPC客户端并连接到Solana网络。
然后,我们使用GetVersion() 方法,通过使用context.TODO() 提供一个请求上下文让服务器接受,来检索当前节点上运行的Solana版本。
最后,我们使用从GetVersion() 返回的err 变量检查操作中的错误,并从response 变量显示网络版本。如果代码运行没有任何错误,说明你已经成功地用Go连接到Solana Mainnet网络。
如果Go由于
"missing go.sum entry"错误而无法运行main.go文件,你需要在终端运行go mod tidy命令来修复丢失的模块条目。
使用Go与Solana网络进行交互
创建一个新的Solana钱包
Solana SDK提供了一个types.NewAccount() 函数,可以返回一个新生成的Solana钱包。让我们看看如何使用它。
package main
import (
"fmt"
"github.com/portto/solana-go-sdk/types"
)
func main() {
// create a new wallet using types.NewAccount()
wallet := types.NewAccount()
// display the wallet public and private keys
fmt.Println("Wallet Address:", wallet.PublicKey.ToBase58())
fmt.Println("Private Key:", wallet.PrivateKey)
}
在这里,我们使用了Solana SDK中的types.NewAccount() 函数,它可以生成新的钱包,然后打印出它的钱包地址(base58的公钥)和私钥(字节片)。
导入一个Solana钱包
Solana SDK提供了三个函数来导入Solana钱包。每个函数都返回一个types.Account 对象,代表一个使用不同形式的私钥的Solana钱包(base58、字节片和十六进制值)。
// import a wallet with base58 private key
types.AccountFromBase58("")
// import a wallet with bytes slice private key
types.AccountFromBytes([]byte{})
// import a wallet with hex private key
types.AccountFromHex("")
让我们看看如何通过其私钥恢复一个Solana钱包。
package main
import (
"fmt"
"github.com/portto/solana-go-sdk/types"
)
func main() {
// create a new wallet
wallet := types.NewAccount()
fmt.Println("Wallet Address:", wallet.PublicKey.ToBase58())
// import the wallet using its private key
importedWallet, err := types.AccountFromBytes(wallet.PrivateKey)
// check for errors
if err != nil {
panic(err)
}
// display the imported wallet public and private keys
fmt.Println("Imported Wallet Address:", importedWallet.PublicKey.ToBase58())
}
在这里,我们使用types.NewAcccount() 函数创建了一个新的钱包,然后使用types.AccountFromBytes() 函数导入钱包并比较它们的地址。如果它们相等,钱包导入就成功了。
取出Solana钱包的余额
因为我们正在创建新的钱包,他们的余额将永远是零。Solana在其JSON RPC API中提供了一个requestAirdrop()方法,为开发目的请求硬币。让我们看看如何使用它。
package main
import (
"context"
"fmt"
"github.com/portto/solana-go-sdk/client"
"github.com/portto/solana-go-sdk/client/rpc"
"github.com/portto/solana-go-sdk/types"
)
func main() {
// create a RPC client
c := client.NewClient(rpc.DevnetRPCEndpoint)
// create a new wallet
wallet := types.NewAccount()
// request for 1 SOL airdrop using RequestAirdrop()
txhash, err := c.RequestAirdrop(
context.TODO(), // request context
wallet.PublicKey.ToBase58(), // wallet address requesting airdrop
1e9, // amount of SOL in lamport
)
// check for errors
if err != nil {
panic(err)
}
fmt.Println("Transaction Hash:", txhash)
}
我们使用RequestAirdrop() ,通过提供请求上下文、钱包公钥(base58)和lamport金额,为Solana钱包请求Devnet币。
RequestAirdrop()函数接受以lamport为单位的amount参数,这是SOL的最小分数单位,类似于比特币的Satoshi。1 lamport ~ 0.000000001 SOL。
你可以使用Solana Devnet Explorer来跟踪你的交易状态。
接下来,使用Solana SDK提供的GetBalance() 方法,从Solana钱包的地址获取其拥有的SOL数量。让我们看看如何使用它。
package main
import (
"context"
"fmt"
"github.com/portto/solana-go-sdk/client"
"github.com/portto/solana-go-sdk/client/rpc"
)
func main() {
// create a RPC client
c := client.NewClient(rpc.DevnetRPCEndpoint)
// fetch the balance using GetBalance()
balance, err := c.GetBalance(
context.TODO(), // request context
"8LdDAFdGuvZdhhnheUv9jVtiv9wQT3eTk2E46FodZP38", // wallet to fetch balance for
)
// check for errors
if err != nil {
panic(err)
}
fmt.Println("Wallet Balance in Lamport:", balance)
fmt.Println("Wallet Balance in SOL:", balance/1e9)
}
将SOLana转移到另一个钱包
在Solana上进行转账之前,你必须遵循四个步骤,以确保你的交易在网络上被创建。
首先,使用GetRecentBlockhash() 功能从网络上检索最新的区块哈希值。
response, err := c.GetRecentBlockhash(context.TODO())
然后,用检索到的区块哈希值和交易签字人的公钥制作一个转账信息。
message := types.NewMessage(
wallet.PublicKey, // public key of the transaction signer
[]types.Instruction{
sysprog.Transfer(
wallet.PublicKey, // public key of the transaction sender
common.PublicKeyFromString(to), // wallet address of the transaction receiver
1e9, // transaction amount in lamport
),
},
response.Blockhash, // recent block hash
)
转移信息包含交易发送方、接收方和金额的公钥。也可以在一个交易中进行多次转账。
用转账信息和交易签字人创建一个交易。
tx, err := types.NewTransaction(message, []types.Account{wallet, wallet})
交易签字人是为该交易支付费用的账户。可以让另一个账户支付交易费用,但该账户也必须签署该交易。
接下来,将交易发送到网络,像这样。
txhash, err := c.SendTransaction2(context.TODO(), tx)
将交易发送到网络后,你会收到它的哈希值,我们可以用它来追踪这笔交易。这里是完整的转账代码。
package main
import (
"context"
"fmt"
"github.com/portto/solana-go-sdk/client"
"github.com/portto/solana-go-sdk/client/rpc"
"github.com/portto/solana-go-sdk/common"
"github.com/portto/solana-go-sdk/program/sysprog"
"github.com/portto/solana-go-sdk/types"
)
func main() {
// create a RPC client
c := client.NewClient(rpc.DevnetRPCEndpoint)
// import a wallet with Devnet balance
wallet, _ := types.AccountFromBytes([]byte{})
// fetch the most recent blockhash
response, err := c.GetRecentBlockhash(context.TODO())
if err != nil {
panic(err)
}
// make a transfer message with the latest block hash
message := types.NewMessage(
wallet.PublicKey, // public key of the transaction signer
[]types.Instruction{
sysprog.Transfer(
wallet.PublicKey, // public key of the transaction sender
common.PublicKeyFromString("8t88TuqUxDMVpYGHcVoXnBCAH7TPrdZ7ydr4xqcNu2Ym"), // wallet address of the transaction receiver
1e9, // transaction amount in lamport
),
},
response.Blockhash, // recent block hash
)
// create a transaction with the message and TX signer
tx, err := types.NewTransaction(message, []types.Account{wallet, wallet})
if err != nil {
panic(err)
}
// send the transaction to the blockchain
txhash, err := c.SendTransaction2(context.TODO(), tx)
if err != nil {
panic(err)
}
fmt.Println("Transaction Hash:", txhash)
}
用Go创建一个Solana钱包
现在你已经学会了如何与Solana网络互动,让我们扩展我们之前创建的代码块,用Go建立一个功能齐全的加密货币钱包。
让我们从为钱包创建一个自定义类型开始。在你的main.go 文件中保存以下代码。
package main
import (
"context"
"github.com/portto/solana-go-sdk/client"
"github.com/portto/solana-go-sdk/common"
"github.com/portto/solana-go-sdk/program/sysprog"
"github.com/portto/solana-go-sdk/types"
)
type Wallet struct {
account types.Account
c *client.Client
}
我们需要一个函数来生成Wallet 类型的新实例,以便我们可以使用它。在main.go 文件中添加以下代码。
func CreateNewWallet(RPCEndpoint string) Wallet {
return Wallet{
types.NewAccount(),
client.NewClient(RPCEndpoint),
}
}
我们可以用我们的应用程序创建新的钱包,通过添加一个函数,使用他们的私钥导入现有的Solana钱包。将以下代码添加到main.go 文件中。
func ImportOldWallet(privateKey []byte, RPCEndpoint string) (Wallet, error) {
wallet, err := types.AccountFromBytes(privateKey)
if err != nil {
return Wallet{}, err
}
return Wallet{
wallet,
client.NewClient(RPCEndpoint),
}, nil
}
现在我们有了创建和导入Solana钱包账户的工作代码。让我们为Wallet 类型创建一些方法。
我们将首先添加一个请求SOL空投和检索钱包余额的函数。在main.go 文件中添加以下代码。
func (w Wallet) RequestAirdrop(amount uint64) (string, error) {
// request for SOL using RequestAirdrop()
txhash, err := w.c.RequestAirdrop(
context.TODO(), // request context
w.account.PublicKey.ToBase58(), // wallet address requesting airdrop
amount, // amount of SOL in lamport
)
if err != nil {
return "", err
}
return txhash, nil
}
func (w Wallet) GetBalance() (uint64, error) {
// fetch the balance using GetBalance()
balance, err := w.c.GetBalance(
context.TODO(), // request context
w.account.PublicKey.ToBase58(), // wallet to fetch balance for
)
if err != nil {
return 0, nil
}
return balance, nil
}
接下来,我们将创建一个函数,将SOL从我们的钱包转移到Solana网络上的其他钱包。将以下代码添加到main.go 文件中。
func (w Wallet) Transfer(receiver string, amount uint64) (string, error) {
// fetch the most recent blockhash
response, err := w.c.GetRecentBlockhash(context.TODO())
if err != nil {
return "", err
}
// make a transfer message with the latest block hash
message := types.NewMessage(
w.account.PublicKey, // public key of the transaction signer
[]types.Instruction{
sysprog.Transfer(
w.account.PublicKey, // public key of the transaction sender
common.PublicKeyFromString(receiver), // wallet address of the transaction receiver
amount, // transaction amount in lamport
),
},
response.Blockhash, // recent block hash
)
// create a transaction with the message and TX signer
tx, err := types.NewTransaction(message, []types.Account{w.account, w.account})
if err != nil {
return "", err
}
// send the transaction to the blockchain
txhash, err := w.c.SendTransaction2(context.TODO(), tx)
if err != nil {
return "", err
}
return txhash, nil
}
现在,我们已经为Wallet 类型创建了所有的方法。让我们来测试一下。
// create a new wallet
wallet := CreateNewWallet(rpc.DevnetRPCEndpoint)
// request for an airdrop
fmt.Println(wallet.RequestAirdrop(1e9))
// make transfer to another wallet
fmt.Println(wallet.Transfer("8t88TuqUxDMVpYGHcVoXnBCAH7TPrdZ7ydr4xqcNu2Ym", 5e8))
// fetch wallet balance
fmt.Println(wallet.GetBalance())
结论
通过探索使用Solana和Go的区块链开发世界,你以最小的努力建立了一个加密货币钱包。我们看到了如何使用solana-go-sdk 包创建和检索Solana钱包,存储、接收和转移硬币。