Rápido Scavenger

Rápido carroñero

Nota

Este tutorial debe ser actualizado.

Bienvenido al mundo de Prompt Scavenger, un juego en el que usarás Celestiaiais Node API y OpenAIays GPT-3.5 para decodificar mensajes ocultos dispersos por la cadena de bloques de Celestiaia. En este tutorial, usaremos Golang para escribir el código del juego.

A través de este tutorial, obtendrá experiencia utilizando la API de Nodo de Celestiaiays para obtener datos de la cadena de bloques, procesarlos y enviar nuevas transacciones con esos datos. Youisll también aprenderá cómo integrar OpenAIays GPT-3.5 API para generar respuestas divertidas basadas en los datos que encontró.

Así que si estás listo para embarcarte en una aventura que combina la tecnología blockchain con el poder de la IA, y aprender algo de Golang en el camino, ¡comencemos!

Dependencias

Se necesitan instalar u obtener las siguientes dependencias:

Instale Celestia Node y ejecute un nodo de luz

Primero, instale el binario celestia-node.

Permite ejecutar los siguientes comandos para obtener nuestra configuración env vars (NOTA: Para CORE_IP puede seleccionar entre el lista de puntos finales RPC disponibles en la página de Blockspace Race:

sh

KEYNAME="scavenger_key"
NODETYPE="light"
NETWORK="blockspacerace"
AUTHTYPE="admin"
CORE_IP=""

A continuación, vamos a generar una clave de billetera para nuestro nodo de luz:

sh

./cel-key add $KEYNAME --keyring-backend test --node.type $NODETYPE --p2p.network $NETWORK

Asegúrese de guardar los mnemónicos y su dirección pública celestia1 en un lugar seguro.

Luego diríjase a nuestro Servidor Discord y solicite tokens desde el #faucet canal bajo Blockspace Race.

Puede rastrear recibir los fondos en el explorador aquí: Interchain Explorer por Cosmostation

Solo asegúrate de pegar tu celestia1**** dirección para buscarlo.

Ejecutaremos esta versión de Celestia Node con la red de prueba Blockspace Race. En primer lugar, vamos a inicializar nuestro nodo:

sh

celestia light init --p2p.network blockspacerace

A continuación, comenzaremos nuestro nodo:

sh

celestia light start --core.ip $CORE_IP --p2p.network $NETWORK --gateway.deprecated-endpoints --gateway --gateway.addr 127.0.0.1 --gateway.port 26659 --keyring.accname $KEYNAME

PUNTA

El --core.ip el puerto GRPC es predeterminado en 9090, por lo que si no lo especifica en la línea de comandos, será predeterminado en ese puerto. Puede agregar el puerto después de la dirección IP o usar el --core.grpc.port marque para especificar otro puerto si lo prefiere.

Consulte la sección de puertos de la página de solución de problemas de celestia-node para obtener información sobre qué puertos deben estar abiertos en su máquina.

Ahora debería tener un nodo de luz en funcionamiento en su máquina. El resto del tutorial supondrá que construirá el script y lo ejecutará donde está el nodo de luz en su localhost.

Clave de autenticación de API de nodo

En la misma máquina donde se está ejecutando el nodo de luz Celestia, ejecute lo siguiente:

sh

export AUTH_TOKEN=$(celestia $NODETYPE auth $AUTHTYPE)

Ahora ejecute lo siguiente para obtener el token de autenticación para su nodo:

sh

echo $AUTH_TOKEN

Esto se utilizará para el archivo env var que configuramos más adelante.

Clave openAI

Asegúrate de ir a OpenAI para registrarse en una cuenta y generar una clave API OpenAI. Se necesitará la clave para comunicarse con OpenAI.

Construyendo el carroñero oportuno

Primero tendremos que configurar un .env archivo con lo siguiente pegado en:

txt

NODE_RPC_IP="http://localhost:26658"
NODE_JWT_TOKEN=""
OPENAI_KEY=""
NAMESPACE_ID="00000000ce1e571a"

los OPENAI_KEY es la clave API que obtuviste de Open AI. Para NODE_RPC_IP, se supone que es el host local, pero puede apuntar a un nodo de luz que sea remoto. NODE_JWT_TOKEN es el AUTH_TOKEN generaste antes. Para la ID de espacio de nombres, hicimos una muestra para que la use, pero puede generar la suya.

¡Ahora, construyamos!

Copiar sobre los archivos Go

Ejecute lo siguiente:

sh

mkdir test_scavenger
git clone https://github.com/celestiaorg/PromptScavenger.git
cp PromptScavenger/go.mod test_scavenger/
cp PromptScavenger/go.sum test_scavenger/
cd test_scavenger

Esto copiará sobre lo requerido go.sum y go.mod archivos a un nuevo directorio que usaremos para importar la biblioteca golang de Node API.

Cree sus declaraciones de importación

Dentro del directorio, cree un main.goarchivar y configurar las declaraciones de importación:

ir

package main

import (
        "context"
        "fmt"
        "log"
        "os"

        "github.com/celestiaorg/celestia-node/api/rpc/client"
        nodeheader "github.com/celestiaorg/celestia-node/header"
        "github.com/celestiaorg/nmt/namespace"
        "github.com/joho/godotenv"
        cosmosmath "cosmossdk.io/math"
        openai "github.com/sashabaranov/go-openai"
        "encoding/base64"
        "encoding/hex"
)

func main() {
  // TODO
}

Aquí configuramos todas las bibliotecas requeridas que necesitamos usar más el main función que usaremos para nuestro juego.

Funciones útiles

Primero tendremos que crear algunas funciones útiles que necesitará más adelante.

ir

// loadEnv loads environment variables from the .env file.
func loadEnv() {
        err := godotenv.Load(".env")
        if err != nil {
                log.Fatal("Error loading .env file")
        }
}

El loadEnv la función nos permite cargar nuestro .env archivo que tiene todos los env var necesarios necesarios.

A continuación, permite crear una función de ayuda que nos permite cargar una instancia del cliente Celestia Node dado el env vars correcto pasado a él:

ir

// createClient initializes a new Celestia node client.
func createClient(ctx context.Context) *client.Client {
        nodeRPCIP := os.Getenv("NODE_RPC_IP")
        jwtToken := os.Getenv("NODE_JWT_TOKEN")

        rpc, err := client.NewClient(ctx, nodeRPCIP, jwtToken)
        if err != nil {
                log.Fatalf("Error creating client: %v", err)
        }

        return rpc
}

Como puede ver, aquí el cliente Celestia Node incluye la IP de Node RPC y el Token JWT que configuramos anteriormente.

Ahora, si volvemos a nuestro main función, podemos hacer lo siguiente para configurar y cargar nuestro env y cliente:

ir


func main() {
  ctx, cancel := context.WithCancel(context.Background())
  defer cancel()
  loadEnv()

  // Close the client when you are finished
  client.Close()
}

Aquí, configuramos un flujo de trabajo que nos permite cargar nuestros env vars, instanciar al cliente con él y luego cerrar el cliente.

Ahora, permitas construir algunas funciones más útiles:

ir

func createNamespaceID() []byte {
        nIDString := os.Getenv("NAMESPACE_ID")
        data, err := hex.DecodeString(nIDString)
        if err != nil {
                log.Fatalf("Error decoding hex string:", err)
        }
        // Encode the byte array in Base64
        base64Str := base64.StdEncoding.EncodeToString(data)
        namespaceID, err := base64.StdEncoding.DecodeString(base64Str)
        if err != nil {
                log.Fatalf("Error decoding Base64 string:", err)
        }
        return namespaceID
}

Aquí, estamos creando una función útil llamada createNameSpaceID que dada una cadena para un ID de espacio de nombres, puede decodificar la cadena hexadecimal, codificarla después a una matriz de bytes, luego decodificarlo como una cadena base64 que es necesaria para la API de Nodo.

Tendremos que crear solo algunas funciones más antes de terminar las cosas.

ir

// postDataAndGetHeight submits a new transaction with the
// provided data to the Celestia node.
func postDataAndGetHeight(client *client.Client, namespaceID namespace.ID, payLoad [
]byte, fee cosmosmath.Int, gasLimit uint64) uint64 {
        response, err := client.State.SubmitPayForBlob(context.Background(), namespa
ceID, payLoad, fee, gasLimit)
        if err != nil {
                log.Fatalf("Error submitting pay for blob: %v", err)
        }
        fmt.Printf("Got output: %v", response)
        height := uint64(response.Height)
        fmt.Printf("Height that data was submitted at: %v", height)
        return height
}

En la función postDataAndGetHeight, le mostramos cómo enviar un mensaje a un ID de espacio de nombres específico proporcionado en Celestia. Después de un envío exitoso, la función le devuelve la altura del bloque en el que se envió.

A continuación, implemente la siguiente función:

ir

func getDataAsPrompt(client *client.Client, height uint64, namespaceID namespace.ID)
 string {
        headerParam := getHeader(client, height)
        response, err := client.Share.GetSharesByNamespace(context.Background(), hea
derParam.DAH, namespaceID)
        if err != nil {
                log.Fatalf("Error getting shares by namespace data for block height:
 %v. Error is %v", height, err)
        }
        var dataString string
        for _, shares := range response {
                for _, share := range shares.Shares {
                        dataString = string(share[8:])
                }
        }
        return dataString
}

En la función getDataAsPrompt, mostramos una función útil que da una altura de bloque particular y un ID de espacio de nombres, puede devolver los datos de bloque (llamados shares aquí) que luego convertimos a una cadena y devolverlos.

Finalmente, implementamos una función de ayuda GPT-3.5 que, dado un mensaje, devuelve una declaración:

ir

// gpt3 processes a given message using GPT-3 and prints the response.
func gpt3(msg string) {
        // Set the authentication header
        openAIKey := os.Getenv("OPENAI_KEY")
        client := openai.NewClient(openAIKey)
        resp, err := client.CreateChatCompletion(
                context.Background(),
                openai.ChatCompletionRequest{
                        Model: openai.GPT3Dot5Turbo,
                        Messages: []openai.ChatCompletionMessage{
                                {
                                        Role:    openai.ChatMessageRoleUser,
                                        Content: msg,
                                },
                        },
                },
        )

        if err != nil {
                fmt.Printf("ChatCompletion error: %v\n", err)
                return
        }
        fmt.Println(resp.Choices[0].Message.Content)
}

Envolviendo las funciones

Ahora, actualizaremos nuestro mainfunción para incluir la lógica de las funciones que construimos donde le mostramos cómo hacer lo siguiente:

  • Instantiate namespace ID, tarifa, límite de gas y GPT prompt

  • Envíe el mensaje de GPT como una transacción de PayForBlob y luego recupere la Altura del Bloque

  • Recupere el Símbolo de esa Altura de Bloque como un Compartir Datos y conviértalo en una cadena y devuélvalo

  • Envíe esa cadena a la función GPT para obtener una salida rápida

ir

func main() {
        ctx, cancel := context.WithCancel(context.Background())
        defer cancel()
        loadEnv()
        var namespaceID namespace.ID = createNamespaceID()
        client := createClient(ctx)
        var gasLimit uint64 = 6000000
        fee := cosmosmath.NewInt(10000)
        var gptPrompt string = "What are modular blockchains?"
        prompt := []byte{0x00, 0x01, 0x02}
        prompt = append(prompt, []byte(gptPrompt)...)
        height := postDataAndGetHeight(client, namespaceID, prompt, fee, gasLimit)
        promptString := getDataAsPrompt(client, height, namespaceID)
        gpt3(promptString)
        // Close the client when you are finished
        client.Close()
}

¡Y ahora tienes la versión final del juego!

Ejecute el script golang con el siguiente comando:

sh

go run main.go

Después de un tiempo, publicará la salida del mensaje que envió a OpenAI que sacó de la cadena de bloques de Celestiaia.

Próximos pasos

Con este tutorial, pudo construir una transacción PFB, enviarla a Celestia, recuperarla de Celestia y decodificar su contenido, luego para obtener una bonificación adicional, envíe el mensaje a GPT-3.5.

Para los próximos pasos, lanzaremos misiones a este tutorial donde los usuarios deberán completar desafíos que ayuden a familiarizarlos con la capa de Disponibilidad de Datos de Celestia.

Last updated