我们很高兴地宣布Flow社区存档节点的开放测试。归档节点提供了一种可扩展的、有效的方式来访问Flow协议的执行状态历史,**为当前的spork。它可以用来查询账户细节,并使用gRPC访问API在从当前spork开始到最新密封块的任何给定块执行脚本。
什么是归档节点?
Flow的多节点架构提供了面向未来的扩展,它将共识与执行分开,并有几个资源丰富的执行节点来执行交易。这些执行节点被设计为将执行状态数据(Flow账户、智能合约、资源等的状态)保存在内存中,以便更快地访问。然而,考虑到状态将继续无限地增长,执行节点被设计为在内存中只保留最近的状态,追溯到过去的100个区块左右。因此,需要一个有效的解决方案,为任何想要查询过去某个区块的状态的应用程序提供过去100个区块以上的旧的或存档的执行状态数据。归档节点旨在提供这种解决方案并提供归档数据。
归档节点是一个跟随链条的节点,它存储并索引协议和执行状态。它允许只读查询,如需要执行状态寄存器值的脚本执行。它可以用来回答任何来自过去数据的查询,例如,"在X高度的Flow账户余额是多少?"其中X是过去的几千个块。
归档节点是如何工作的?
和观察者节点一样,归档节点也是一个未加密的节点,并与上游的访问节点进行通信。观察者节点只接收协议状态数据(块、集合、事务等),而归档节点同时接收协议状态和执行状态数据。
谁应该使用档案节点?
- 需要访问历史数据的dApps,例如,CAST,它在过去的区块中考虑到了用户的账户余额
- 需要访问历史数据的连锁分析和审计工具
用于数据检索的不同节点 - 归档节点VS访问节点VS观察者节点
在讨论归档节点与访问节点和观察者节点的区别之前,首先让我们看看Flow中的两类状态数据。由于Flow有不同类型的节点,而不是单一的验证器节点,所以不是所有的节点类型都有所有的数据。Flow的状态数据分为协议状态数据和执行状态数据。
协议状态是指Flow网络协议的运行状态,包括身份表和Flow网络中节点产生的资源:区块、集合、收据、批准、印章等。
执行状态是Flow账户、智能合约、资源等的状态。这种状态只完整地存储在执行节点上。
访问节点是一个有桩节点,它接收和索引所有的协议状态数据,并为访问API服务。它可以通过查询其本地数据库来回复所有与协议状态相关的Access API调用,如GetBlock、GetAccount、GetCollection等。然而,对于所有与执行状态相关的调用,如GetAccount、ExecuteScriptAtXXX,它对执行节点进行上游调用以获取执行状态数据。
今年早些时候,观察者节点被推出,作为访问节点的一个无桩替代方案,任何人都可以运行该节点而不需要桩。像访问节点一样,观察者节点也为访问API服务。它只接收和索引最新的区块数据,并将所有的访问API调用委托给上游的访问节点,而不是区块数据的调用。
今天,人们可以很容易地查询访问节点或观察者节点的最新区块的账户余额,或在最新区块执行脚本,但是你不能查询账户余额或在过去任何任意区块执行脚本,这样做你会得到如下错误,因为执行节点不保留过去100个区块以上的执行状态数据。
rpc错误: code = Internal desc = failed to get account: failed to get account at block (xxx): state commitment not found (yyy).这个错误通常发生在这个脚本的参考块没有设置为最近的块。
这就是归档节点的作用。
与访问节点和观察者节点不同,存档节点除了协议状态数据外,还存储和索引执行状态。然后,它可以通过其本地数据库回复执行状态的访问API调用,如GetAccount。
- 如果你想访问最新的区块、交易等,但不想运行一个节点,可以使用Flow社区访问节点。
- 如果你想要一个单一的租约和/或不想受制于访问API的速率限制,可以考虑运行你自己的访问节点。
- 如果你想要一个本地运行的节点,提供最新的区块数据,请运行一个观察者节点。
- 如果你想访问历史执行状态数据,请使用社区存档节点。
API
归档节点提供了一个简洁的gRPC访问API版本,其中包括以下三个调用。
- 执行ScriptAtBlockID
- 在BlockHeight上执行Script
- 获取帐户的高度(GetAccountAtBlockHeight
对于所有其他的Access API调用,它返回HTTP错误501未执行。
gRPC API的端点是:archive.mainnet.nodes.onflow.org:9000
实例
1.要获得当前spork开始时的账户余额,可以调用档案节点的GetAccountAtBlockHeight。
样品代码。
package main
import (
"context"
"fmt"
"github.com/onflow/flow-go-sdk/access/grpc"
"github.com/onflow/flow-go-sdk"
)
func main() {
// the Flow community archive API endpoint
archiveNodeAddress := "archive.mainnet.nodes.onflow.org:9000"
// create a gRPC client for the Archive node
archiveNodeClient, err := grpc.NewClient(archiveNodeAddress)
if err != nil {
fmt.Println("err:", err.Error())
panic(err)
}
ctx := context.Background()
addr := flow.HexToAddress("e467b9dd11fa00df") // any Flow account address
// get Account balance at the start height of the current spork
// <https://developers.flow.com/nodes/node-operation/past-sporks#mainnet-20>
account, err := archiveNodeClient.GetAccountAtBlockHeight(ctx, addr, 40171634)
if err != nil {
fmt.Println("err:", err.Error())
panic(err)
}
fmt.Println(account.Balance)
}
2.要在过去的某个区块执行脚本,可以在存档节点上调用ExecuteScriptAtBlockHeight或ExecuteScriptAtBlockID调用。
样品代码。
package main
import (
"context"
"fmt"
"github.com/onflow/cadence"
"github.com/onflow/flow-go-sdk/access/grpc"
)
func main() {
// the Flow mainnet community Access node API endpoint
accessNodeAddress := "access.mainnet.nodes.onflow.org:9000"
// the Flow community archive API endpoint
archiveNodeAddress := "archive.mainnet.nodes.onflow.org:9000"
// create a gRPC client for the Access node
accessNodeClient, err := grpc.NewClient(accessNodeAddress)
if err != nil {
fmt.Println("err:", err.Error())
panic(err)
}
ctx := context.Background()
// get the height of the latest sealed block from the Flow mainnet community access node
latestBlockHeader, err := accessNodeClient.GetLatestBlockHeader(ctx, true)
if err != nil {
fmt.Println("err:", err.Error())
panic(err)
}
// set height to 500 blocks in the past
height := latestBlockHeader.Height - 500
// create a gRPC client for the Archive node
archiveNodeClient, err := grpc.NewClient(archiveNodeAddress)
if err != nil {
fmt.Println("err:", err.Error())
panic(err)
}
script := []byte(`
pub fun main(a: Int): Int {
return a + 10
}
`)
args := []cadence.Value{cadence.NewInt(5)}
// execute script on the archive node at a block height which is 500 blocks in the past
value, err := archiveNodeClient.ExecuteScriptAtBlockHeight(ctx, height, script, args)
if err != nil {
fmt.Println("err:", err.Error())
panic(err)
}
fmt.Printf("\\nValue: %s", value)
}
限制条件
- gRPC API速率限制
- 目前不支持Access REST API和gRPC-web端点。
- 归档节点目前不能自我托管。
- 档案节点只能回溯到当前spork的开始。
节点状态
归档节点的状态可以从Flow状态页面的 "Flow主网归档节点组件 "中监控。
下一步是什么 🚀
这是一个开放性的测试版本,我们将解决一些问题,并为明年年初的GA发布做好准备。
社区归档节点将始终可用,明年初,将有一个归档节点的自我托管版本,任何人都可以运行,这是通往无权限节点操作路线图的一部分。这个测试版的推出是实现这一目标的一个垫脚石。
反馈 ❤️
我们重视你的反馈。请在这里报告你在使用存档节点时发现的任何问题:https://github.com/onflow/flow-archive/issues。