本文转载自微信公众号《区块链研究实验室》,作者连三丰。转载本文请联系区块链研究实验室公众号。过去,开发人员通过构建自己的中心化索引服务器从区块链中提取数据,将数据存储在数据库中,并通过API公开。这需要大量的工程和硬件资源,并破坏了去中心化所需的重要安全性。本文将向您展示如何在去中心化网络基础设施——区块链数据上轻松部署API。去中心化Web基础设施分布式互联网的思想和方向通常被称为Web3,Web3通过以下附加功能增强了我们今天所知的互联网:去中心化可验证的无信任自治为了实现去中心化,协议定义了网络,这些网络提供了一个一系列数字服务,例如计算、存储、带宽、身份和其他无需中介的网络基础设施。这些协议通常分布在多个节点(服务器)上,使大多数希望成为网络一部分并提供服务的人都能参与。在图上构建在本文中,我们还将研究一个这样的协议Graph,以及我们如何使用存储在以太坊区块链中的数据来构建和部署我们自己的GraphQLAPI。Graph是一种索引协议,用于查询以太坊等区块链和IPFS等网络,任何人都可以构建和发布称为子图的开放API,使数据易于访问。子图定义了您希望通过GraphQLAPI提供的数据、数据源和数据访问模式。作为开发人员,您可以选择使用其他开发人员已经部署的子图,或者定义和部署您自己的子图并使用它。子图由几个主要部分组成:1.GraphQLschemaGraphQLschema定义了你想要保存和查询的数据类型/实体,你还可以在schema中定义关系和全文搜索能力等配置。2.子图清单(yaml配置)清单定义了子图索引的智能合约,它们的ABI,这些合约中要注意的事件,以及如何将事件数据映射到图节点存储并允许查询的实体。3.AssemblyScript映射AssemblyScript映射允许您使用模式中定义的实体类型保存要索引的数据;图CLI还结合使用子图的模式和智能合约的ABI来生成AssemblyScript类型。现在我们已经很好地理解了Graph及其工作原理,让我们开始编写一些代码。在本教程中,我们将构建一个从Zora智能合约查询NTF数据的子图,实现获取NFT及其所有者的查询,并建立它们之间的关系。先决条件:为了成功完成本教程,您应该在计算机上安装Node.js,我建议您使用NVM或FNM来管理Node.js的版本。在GraphExplorer中创建一个Graph项目首先,打开GraphExplorer并登录或创建一个新帐户。接下来,转到仪表板并单击添加子图以创建新的子图。使用以下属性配置子图:子图名称-Zoranft子图子标题-用于查询NFT的子图可选-填写描述和GITHUBURL属性使用GraphCLI初始化新子图接下来,安装GraphCLI:$npminstall-g@graphprotocol/graph-cli#or$yarnglobaladd@graphprotocol/graph-cli安装GraphCLI后,可以使用GraphCLIinit命令初始化一个新的子图。两种方法:1来自示例子图$graphinit--from-example/[]2如果您已经将智能合约部署到以太坊主网或测试网,则来自现有智能合约一种,然后初始化该合约的新子图是启动和运行的简单方法。$graphinit--from-contract\[--network]\[--abi]\/[]在我们的示例中,我们将使用Zora代币合约,因此我们可以通过传递--from-contract标志来从合约地址进行初始化:?Directorytocreatethesubgraphin?Zoranftsubgraph?Ethereumnetwork?Mainnet?Contractaddress?0xabEFBc9fD2F806065b4f3C237d4b59D9A97Bcac7?ContractName·Token此命令将根据作为参数--from-contract传入的合约地址生成基本子图。通过使用这个合约地址,CLI将初始化项目中的一些东西来帮助你开始。子图的主要配置和定义位于subgraph.yaml文件中,子图代码库由几个文件组成:subgraph.yaml:包含子图列表的YAML文件。schema.graphql:GraphQL模式,用于定义为子图存储的数据以及如何通过GraphQL查询数据。AssemblyScript映射:将以太坊中的事件数据转换为架构中定义的实体的AssemblyScript代码。我们将使用的subgraph.yaml中的条目是:description(可选):关于子图的人类可读描述,当子图部署到托管服务时,图浏览器将显示该描述。存储库(可选):可以在其中找到子图清单的存储库的URL。dataSources.source:子图来源的智能合约的地址,以及要使用的智能合约的abi。dataSources.source.startBlock(可选):数据源开始索引的块号。dataSources.mapping.entities:数据源写入存储的实体,每个实体的schema定义在schema.graphql文件中。dataSources.mapping.abis:一个或多个命名的ABI文件,用于源合约和您在映射中与之交互的任何其他智能合约。dataSources.mapping.eventHandlers:列出此子图响应的智能合约事件以及映射中的处理程序(示例中的./src/mapping.ts)将这些事件转换为商店中的实体。使用TheGraph定义实体,您可以在schema.graphql中定义实体类型,GraphNode将生成顶级字段以查询该实体类型的单个实例和集合。每个应该是实体的类型都必须使用@entity指令进行注释。我们将索引的实体/数据是令牌和用户。这样,我们可以索引用户以及用户自己创建的令牌。为此,请使用以下代码更新schema.graphql:typeToken@entity{id:ID!tokenID:BigInt!contentURI:String!metadataURI:String!creator:User!owner:User!}typeUser@entity{id:ID!tokens:[Token!]!@derivedFrom(field:"owner")created:[Token!]!@derivedFrom(field:"creator")}通过@derivedFrom(来自文档)通过“关系”可以通过@derivedFrom实体中的字段上面定义了反向查找。这会在实体上创建一个可以查询但不能通过映射API手动设置的虚拟字段。相反,它源自在另一个实体上定义的关系。对于这样的关系,存储关系的两边意义不大,如果只存储一边,派生另一边,索引和查询性能会更好。现在我们已经为我们的应用程序创建了一个GraphQL模式,我们可以在本地生成实体以开始在由mappingsCLI创建的实体中使用:子图的GraphQL模式和数据源中包含的合约ABI。使用实体和映射更新子图我们现在可以配置subgraph.yaml以使用我们刚刚创建的实体并配置它们的映射。为此,首先使用User和Token实体更新dataSources.mapping.entities字段:entities:-Token-User接下来,更新dataSources.mapping.eventHandlers以仅包含以下两个事件处理程序:eventHandlers:-event:TokenURIUpdated(indexeduint256,address,string)handler:handleTokenURIUpdated-event:Transfer(indexedaddress,indexedaddress,indexeduint256)handler:handleTransfer最后,更新配置以添加startBlock:source:address:"0xabEFBc9fD2F806065b4f3C237d4b59D9A97Bcac7"abi:TokenstartBlock:11565020Assemblyscript映射接下来,打开src/mappings.ts写入我们在子图中定义的映射事件处理程序。使用以下代码更新文件:import{TokenURIUpdatedasTokenURIUpdatedEvent,TransferasTransferEvent,TokenasTokenContract}from"../generated/Token/Token"import{Token,User}from'../generated/schema'exportfunctionhandleTokenURIUpdated(event:TokenURIUpdatedEvent):void{lettoken=Token.load(event.params._tokenId.toString());token.contentURI=event.params._uri;token.save();}exportfunctionhandleTransfer(event:TransferEvent):void{lettoken=Token.load(event.params.tokenId.toString();if(!token){token=newToken(event.params.tokenId.toString());token.creator=event.params.to.toHexString();token.tokenID=event。params.tokenId;lettokenContract=TokenContract.bind(event.address);token.contentURI=tokenContract.tokenURI(event.params.tokenId);token.metadataURI=tokenContract.tokenMetadataURI(event.params.tokenId);}token.owner=event.params.to.toHexString();token.save();letuser=User.load(event.params.to.toHexString());if(!user){user=newUser(event.params.to.toHexString());user.save();}}这个这些映射将处理创建、传输或更新新令牌的事件。当这些事件触发时,地图会将数据保存到子图中。运行构建接下来,让我们运行构建以确保一切都已正确配置。为此,请运行以下构建命令:$graphbuild如果构建成功,您应该会在根目录中看到一个新的构建文件夹。部署子图要进行部署,我们可以使用GraphCLI运行deploy命令。要部署,您首先需要复制在GraphExplorer中创建的子图的访问令牌:接下来,运行以下命令:$graphauthhttps://api.thegraph.com/deploy/$yarndeploy部署子图后,您应该看到它显示在您的仪表板中:当您单击子图时,它应该打开GraphExplorer:查询数据现在我们在仪表板中,我们应该能够开始查询数据。运行以下查询以获取令牌及其元数据列表:{tokens{idtokenIDcontentURImetadataURI}}我们还可以配置顺序方向:{tokens(orderBy:id,orderDirection:desc){idtokenIDcontentURImetadataURI}}或选择跳过某些结果以实现一些基本的分页:{tokens(skip:100,orderBy:id,orderDirection:desc){idtokenIDcontentURImetadataURI}}或查询用户及其相关内容:{users{idtokens{idcontentURI}}}如果我们想要对更新子图应该如果图形进行了一些更改然后重新部署,我们会怎么做?假设我们要向子图添加新功能,假设除了现有的查询功能之外,我们还想添加按创建NFT时的时间戳进行排序的功能。为此,我们需要先为实体添加一个新的createdAtTimestamp字段Token:typeToken@entity{id:ID!tokenID:BigInt!contentURI:String!metadataURI:String!creator:User!owner:User!"AddnewcreatedAtTimesampfield"createdAtTimestamp:大整数!现在,我们可以重新运行代码生成:graphcodegen接下来,我们需要更新地图以保存这个新字段://updatethehandleTransferfunctiontoaddthecreatedAtTimestamptothetokenobjectexportfunctionhandleTransfer(event:TransferEvent):void{lettoken=Token.load(event.params.tokenId.toString());if(!token){token=newToken(event.params.tokenId.toString());token.creator=event.params.to.toHexString();token.tokenID=event.params.tokenId;//AddthecreatedAtTimestamptothetokenobjecttoken.createdAtTimestamp=event.block.timestamp;lettokenContract=TokenContract.bind(event.address);token.contentURI=tokenContract.tokenURI(event.params.tokenId);token.metadataURI=tokenContract.tokenMetadataURI(event.params.tokenId));}token.owner=event.params.to.toHexString();token.save();letuser=User.load(event.params.to.toHexString());if(!user){user=newUser(event.params.to.toHexString());user.save();}}现在我们可以重新部署子图了:$yarndeploy子图重新部署后,我们现在可以通过时间戳查询到Checkout最近创建的NFTS:{tokens(orderBy:createdAtTimestamp,orderDirection:desc){idtokenIDcontentURImetadataURI}}}【编者推荐】为什么以太坊近期持续暴涨?为什么比特币总市值在以太坊大涨的情况下暴跌?益博睿API泄露美国人大量信用评分数据如何从C++Addon看Napi的实现比特币和以太坊如何解决合法化问题?