Saltar al contenido principal

Transacciones – Referencia del Go SDK

Descripción general

El Go SDK expone un pequeño conjunto de tipos y métodos para:

  • Cargar un wallet
  • Abrir una sesión de transaction contra un node
  • Construir, firmar y enviar una transaction
  • Inspeccionar la transaction resultante y su estado

Esta página documenta esos tipos y métodos principales como referencia rápida. Los tutoriales y ejemplos de extremo a extremo se encuentran en páginas separadas.


Imports

import (
"github.com/ULedgerInc/go-sdk/pkg/wallet"
"github.com/ULedgerInc/go-sdk/pkg/transaction"
)

Carga del wallet

wallet.FromJson

func FromJson(raw string, passphrase string) (UL_Wallet, error)

Carga un wallet cifrado o en texto plano desde una cadena JSON y devuelve una instancia de UL_Wallet, que luego se utiliza para firmar transactions.

Uso en tu CLI:

w, err := wallet.FromJson(rawWallet, passphrase)
if err != nil {
return fmt.Errorf("error loading wallet: %w", err)
}
fmt.Printf("Loaded wallet: %+v\n", w)

El UL_Wallet devuelto expone:

  • Address – la dirección del wallet
  • GetKey() – devuelve la clave subyacente, utilizada para firmar compromisos y descubrir el KeyType.

Sesión de transaction

Tipo: UL_TransactionSession

type UL_TransactionSession struct {
nodeEndpoint string
suggestor string
wallet wallet.UL_Wallet
}

Una sesión de transaction encapsula:

  • El node endpoint (URL base del node)
  • El suggestor (ID del node utilizado para la transaction)
  • El wallet usado para firmar la transaction

Normalmente se obtiene mediante el constructor:

transaction.NewUL_TransactionSession

func NewUL_TransactionSession(
nodeEndpoint string,
wallet wallet.UL_Wallet,
) (UL_TransactionSession, error)

Lo que hace:

  1. Llama a GET {nodeEndpoint}/health para obtener los metadatos del node (nodeId, versión, información de chains).
  2. Llama a GET {nodeEndpoint}/blockchains para asegurarse de que al menos un blockchain esté disponible.
  3. Devuelve un UL_TransactionSession con:
    • nodeEndpoint configurado
    • suggestor configurado con el ID del node
    • wallet configurado con el UL_Wallet proporcionado

Ejemplo:

session, err := transaction.NewUL_TransactionSession(
testConfig.NodeEndpoints[n],
*wallet,
)
if err != nil {
return fmt.Errorf("error creating transaction session: %w", err)
}

(*UL_TransactionSession).GenerateTransaction

func (session *UL_TransactionSession) GenerateTransaction(
input ULTransactionInput,
) (ULTransaction, error)

Responsabilidades de alto nivel:

  1. Rellenar metadatos en ULTransactionInput:

    • Establece input.Suggestor con session.suggestor
    • Establece input.SenderTimestamp con la hora UTC actual
    • Para payloads que no sean CREATE_WALLET ni ALTER_WALLET, establece input.From con session.wallet.Address
    • Establece input.KeyType basándose en session.wallet.GetKey().GetType()
  2. Calcular el compromiso y el payload root:

    • Para DEPLOY_SMART_CONTRACT, UPGRADE_SMART_CONTRACT, TX_CREATE_WALLET, TX_ALTER_WALLET:

      • Llama a input.GetUnboundCommitment(hasher)
      • Establece input.PayloadRoot con el root devuelto (codificado en hex)
    • Para otros tipos de transaction:

      • Llama a input.GetSignatureCommitment(hasher, true) para construir un compromiso Merkle
      • Llama a input.HashSignatureCommitment(hasher, commitment) para obtener el hash del compromiso
      • Establece input.PayloadRoot con el Merkle payload root
  3. Firmar el compromiso:

    • Firma el compromiso con session.wallet.GetKey().SignData(commitment)
    • Establece input.SenderSignature con la firma codificada en hex
  4. Enviar al node:

    • Envía JSON mediante POST a:

      POST {nodeEndpoint}/blockchains/{blockchainId}/transactions
    • Espera 200 OK o 201 Created

    • Deserializa la respuesta en un ULTransaction

Ejemplo:

tx, err := session.GenerateTransaction(input)
if err != nil {
return fmt.Errorf("error generating transaction: %w", err)
}

if tx.TransactionId == "" {
return fmt.Errorf("generated transaction has empty transaction ID")
}

fmt.Printf("Transaction: %+v\n", tx)

Tipos de transaction

ULTransactionInput

Campos utilizados para crear una transaction:

type ULTransactionInput struct {
BlockchainId string `json:"blockchainId"`
To string `json:"to"`
From string `json:"from"`
Payload string `json:"payload"`
SenderSignature string `json:"senderSignature"`
PayloadType string `json:"payloadType"`
Suggestor string `json:"suggestor"`
SenderTimestamp time.Time `json:"senderTimestamp"`
PayloadRoot string `json:"payloadRoot"`
KeyType crypto.KeyType `json:"keyType"`
}

Uso típico para una transaction de tipo DATA:

input := transaction.ULTransactionInput{
Payload: fmt.Sprintf("test %v %d", wallet.Address, n*i),
From: wallet.Address, // overridden by session for most types
To: wallet.Address,
BlockchainId: blockchainId,
PayloadType: transaction.TX_DATA.String(),
}

La mayoría de los campos son rellenados por GenerateTransaction (firma, marcas de tiempo, suggestor, tipo de clave y PayloadRoot).

ULTransactionOutput

Campos devueltos por el node:

type ULTransactionOutput struct {
TransactionId string `json:"transactionId"`
BlockHeight int `json:"blockHeight"`
Clock VectorClock `json:"vectorClock"`
Timestamp Timestamp `json:"timestamp"`
Version string `json:"version"`
Weight int `json:"weight"`
Status string `json:"status"`
Output string `json:"output"`
Proof string `json:"proof"`
ProofVersion string `json:"proofVersion"`
}

ULTransaction

type ULTransaction struct {
ULTransactionInput
ULTransactionOutput
}

Combina tanto los campos de input (lo que solicitaste) como los campos de output (lo que devolvió el node).


Helpers e interfaces de transaction

Interfaz Transaction

type Transaction interface {
GetVectorClock() VectorClock
GetTimestamp() Timestamp
GetTransactionId() string
GetTransactionSignatureBody() string
SetTransactionWeight()
}

ULTransaction implementa esta interfaz (excepto GetTransactionSignatureBody, que no se muestra en el fragmento proporcionado pero forma parte del contrato conceptual).

Métodos en *ULTransaction

func (t *ULTransaction) GetVectorClock() VectorClock
func (t *ULTransaction) GetTimestamp() Timestamp
func (t *ULTransaction) GetTransactionId() string
func (t *ULTransaction) SetTransactionWeight()
func (t *ULTransaction) ToBytes() ([]byte, error)
  • GetVectorClock() – devuelve el reloj vectorial causal para esta transaction.
  • GetTimestamp() – devuelve la estructura Timestamp (tiempos exactos y aproximados).
  • GetTransactionId() – devuelve el ID de transaction asignado por el node.
  • SetTransactionWeight() – recalcula y establece t.Weight basándose en las longitudes de los campos.
  • ToBytes() – serializa la transaction a bytes JSON.

TransactionFromBytes

func TransactionFromBytes(data []byte) (*ULTransaction, error)

Deserializa un slice de bytes JSON en un ULTransaction.


Enums y helpers de análisis de transactions

Estado: UL_TransactionStatus

type UL_TransactionStatus int

const (
INVALID_TX_STATUS UL_TransactionStatus = 0
TX_SUBMITTED UL_TransactionStatus = 1
TX_ACCEPTED UL_TransactionStatus = 2
TX_REJECTED UL_TransactionStatus = 3
)

func (ts UL_TransactionStatus) String() string
func ParseTransactionStatus(str string) (UL_TransactionStatus, error)

Tipo: ULTransactionType

type ULTransactionType int

const (
INVALID_TX_TYPE ULTransactionType = iota
TX_DATA
TX_CREATE_WALLET
TX_ALTER_WALLET
DEPLOY_SMART_CONTRACT
INVOKE_SMART_CONTRACT
UPGRADE_SMART_CONTRACT
ROLLBACK_SMART_CONTRACT
)

func (tt ULTransactionType) String() string
func ParseTransactionType(str string) (ULTransactionType, error)

Valores comunes:

  • TX_DATA – transaction de datos genérica
  • TX_CREATE_WALLET / TX_ALTER_WALLET – transactions de gestión de wallet
  • DEPLOY_SMART_CONTRACT, INVOKE_SMART_CONTRACT, UPGRADE_SMART_CONTRACT, ROLLBACK_SMART_CONTRACT – operaciones de smart contract

Output: UL_TransactionOutput

type UL_TransactionOutput int

const (
INVALID_TX_OUTPUT UL_TransactionOutput = 0
TO_BE_PROCESSED UL_TransactionOutput = 1
TX_SUCCESS UL_TransactionOutput = 2
TX_REJECTED_BY_DUPLICATE UL_TransactionOutput = 3
TX_REJECTED_BY_UNEXISTING UL_TransactionOutput = 4
TX_REJECTED_BY_DISABLED UL_TransactionOutput = 5
TX_REJECTED_BY_UNAUTHORIZED UL_TransactionOutput = 6
TX_REJECTED_BY_INVALID_SIGNATURE UL_TransactionOutput = 7
TX_TRANSACTION_ERROR UL_TransactionOutput = 8
)

func (tt UL_TransactionOutput) String() string
func ParseTransactionOutput(str string) (UL_TransactionOutput, error)

Estos valores corresponden al campo de cadena Output devuelto en ULTransactionOutput.Output.


Compromisos y árboles Merkle (avanzado)

Para casos de uso avanzados donde se necesita control manual sobre los compromisos o la verificación, el SDK expone helpers en ULTransactionInput y constructores de árboles Merkle.

Helpers de compromiso en *ULTransactionInput

func (t *ULTransactionInput) GetSignatureCommitment(
hasher hash.Hash,
computeRoot bool,
) (TransactionCommitment, error)

func (t *ULTransactionInput) GetUnboundCommitment(
hasher hash.Hash,
) ([]byte, error)

func (t *ULTransactionInput) HashSignatureCommitment(
hasher hash.Hash,
commitment TransactionCommitment,
) ([]byte, error)

Utilizados internamente por GenerateTransaction para:

  • Construir raíces Merkle sobre el payload
  • Vincular BlockchainId, From, To, Suggestor, la marca de tiempo y el payload root en un único hash de compromiso
  • Producir los datos que finalmente son firmados por la clave del wallet

Helpers de Merkle

func GenerateMerkleTreeWithHardBound(
payload []byte,
modulus *big.Int,
chunkSize int,
depth int,
hasher hash.Hash,
proofIndex uint64,
) ([]byte, [][]byte, []byte, uint64, error)

func GenerateMerkleTree(
payload []byte,
modulus *big.Int,
chunkSize int,
hasher hash.Hash,
proofIndex uint64,
) ([]byte, [][]byte, []byte, uint64, int, error)

Estas funciones:

  • Dividen el payload en fragmentos
  • Construyen un árbol Merkle
  • Devuelven:
    • La raíz Merkle
    • Los elementos de prueba
    • El fragmento utilizado para las pruebas
    • El número de hojas
    • (para GenerateMerkleTree) la profundidad del árbol

Payloads de smart contract y serializador

Además de los payloads estándar de tipo TX_DATA, el SDK también expone tipos y helpers dedicados para interactuar con smart contracts, lo que permite modelar llamadas a contratos, actualizaciones y rollbacks como payloads JSON que pueden enviarse a través del mismo flujo de transaction.

Estructuras de payload de contrato

type ContractArgs struct {
Value []byte `json:"value"`
}

type InvokeContractPayload struct {
FunctionName string `json:"functionName"`
Args []ContractArgs `json:"args"`
GasLimit uint64 `json:"gasLimit"`
}

type RollbackContractPayload struct {
TargetVersion uint64 `json:"targetVersion"`
RollbackReason string `json:"rollbackReason,omitempty"`
}

type UpgradeContractPayload struct {
NewSourceCode string `json:"newSourceCode"`
UpgradeReason string `json:"upgradeReason,omitempty"`
}

Estas estructuras deben ser codificadas en JSON y colocadas en ULTransactionInput.Payload cuando:

  • PayloadType == INVOKE_SMART_CONTRACT.String()
  • PayloadType == UPGRADE_SMART_CONTRACT.String()
  • PayloadType == ROLLBACK_SMART_CONTRACT.String()

Serializador de la VM del contrato

El serializador codifica valores de Go en el formato binario esperado por la VM de smart contracts de ULedger.

type ContractDataType byte

const (
TypeNull ContractDataType = 0
TypeBool ContractDataType = 1
TypeInt32 ContractDataType = 2
TypeInt64 ContractDataType = 3
TypeString ContractDataType = 4
TypeBytes ContractDataType = 5
TypeArray ContractDataType = 6
TypeMap ContractDataType = 7
TypeFloat32 ContractDataType = 8
TypeFloat64 ContractDataType = 9
)

func Encode(data interface{}) ([]byte, error)
func Decode(data []byte) (interface{}, error)
func GetType(data []byte) (ContractDataType, error)

A alto nivel:

  • Encode – toma valores de Go (bool, int32, string, []byte, map[string]interface{}, []interface{}, etc.) y devuelve un blob binario para la VM.
  • Decode – invierte ese proceso (principalmente útil para herramientas, pruebas o decodificación fuera de la cadena).
  • GetType – inspecciona el primer byte y devuelve el ContractDataType codificado.

Estas herramientas se utilizan principalmente al construir los argumentos para llamadas a smart contracts y se tratarán con mayor profundidad en una guía dedicada a "Smart contracts".


Esta página está pensada como una referencia. Para guías paso a paso, consulta nuestra sección de tutoriales.