Go-Ethereum (Geth) का ethclient पैकेज Ethereum नेटवर्क पर JSON-RPC रिक्वेस्ट्स के लिए एक API रैपर प्रदान करता है, जो web3.js और ethers.js के समान है।
हालाँकि, JSON-RPC की कुछ क्षमताएं, जैसे transaction tracing, ethclient (और web3.js तथा ethers.js) के API में उजागर (exposed) नहीं हैं।
यह ट्यूटोरियल दिखाता है कि उन कार्यों के लिए ethclient का उपयोग कैसे करें जहाँ ethclient JSON-RPC कॉल का समर्थन करता है और जहाँ यह नहीं करता है।
जैसा कि नीचे दिया गया आरेख (diagram) दर्शाता है, कभी-कभी हम ethclient में एक API का उपयोग करके कोई कार्य पूरा कर सकते हैं, लेकिन कभी-कभी हमें RPC कॉल स्वयं तैयार करनी पड़ती है:

ट्यूटोरियल के अंत में, हम दिखाएंगे कि blob transaction को कैसे execute किया जाए, जिसके लिए Ethereum ने हाल ही में Decun अपग्रेड में समर्थन (support) जोड़ा है।
हम कुछ Ethereum transaction से संबंधित concepts जैसे digital signatures को sign करना और verify करना भी निष्पादित (perform) करेंगे।
पूर्वापेक्षाएँ
- आपके कंप्यूटर पर Go भाषा स्थापित (installed) होनी चाहिए; यदि नहीं, तो डाउनलोड निर्देश देखें।
- बेसिक Go प्रोग्रामिंग का ज्ञान।
शुरुआत करना
हम इस पूरे ट्यूटोरियल में Sepolia नेटवर्क का उपयोग करेंगे, लेकिन जो हम दिखाएंगे वह mainnet या अन्य testnets पर भी काम करेगा। सुनिश्चित करें कि आपके पास Sepolia ETH है।
इस ट्यूटोरियल में हम जो ऑपरेशन्स करेंगे:
- नेटवर्क पर सुझाए गए (suggested) gas price को प्राप्त करना
- किसी transaction के लिए gas का अनुमान (estimate) लगाना
- एक EIP1559 raw transaction बनाना और भेजना
- Ethereum मैसेजेस को sign और verify करना
- किसी अकाउंट का nonce (transaction की संख्या) प्राप्त करना
- किसी transaction को trace करना
- अंत में, एक EIP-4844 blob transaction भेजना
शुरू करने के लिए, एक नया प्रोजेक्ट फोल्डर बनाएं, इसे खोलें और इसके साथ initialize करें:
go mod init eth-rpc
हमने अभी अपना प्रोजेक्ट मॉड्यूल बनाया है। यदि वह सफल रहा, तो आपको एक ‘go.mod’ फ़ाइल दिखाई देनी चाहिए जो इस तरह दिखती है

आवश्यक dependencies स्थापित (install) करें:
go get -u github.com/ethereum/go-ethereum@v1.13.14
go get github.com/ethereum/go-ethereum/rpc@v1.13.14
यह एक ‘go.sum’ फ़ाइल उत्पन्न (generate) करेगा।
समस्या निवारण टिप (Troubleshooting Tip):
यदि आपको मॉड्यूल से संबंधित समस्याओं का सामना करना पड़ता है, तो निम्नलिखित प्रयास करें:
-
अपनी ‘go.mod’ और ‘go.sum’ फ़ाइलें हटाएं और इसे
go mod init eth-rpcके साथ फिर से initialize करें। -
dependencies को सिंक्रोनाइज़ करने के लिए
go mod tidyचलाएँ। -
यदि समस्या बनी रहती है, तो
go clean -modcacheके साथ अपने मॉड्यूल कैश को साफ़ करें और चरण 1 और 2 दोहराएँ।
अब निम्नलिखित कोड को प्रोजेक्ट के अंदर ‘main.go’ फ़ाइल में पेस्ट करें:
package main
import "fmt"
const (
sepoliaRpcUrl = "https://rpc.sepolia.ethpandaops.io" // sepolia rpc url
mainnetRpcUrl = "https://rpc.builder0x69.io/" // mainnet rpc url
from = "0x571B102323C3b8B8Afb30619Ac1d36d85359fb84"
to = "0x4924Fb92285Cb10BC440E6fb4A53c2B94f2930c5"
data = "Hello Ethereum!"
privKey = "2843e08c0fa87258545656e44955aa2c6ca2ebb92fa65507e4e5728570d36662"
gasLimit = uint64(21500) // adjust this if necessary
wei = uint64(0) // 0 Wei
)
func main() {
fmt.Println("using ethclient...")
}
जैसे-जैसे हम आगे बढ़ेंगे हम main.go फ़ाइल को अपडेट करेंगे।
आप इसे go run main.go के साथ चला सकते हैं।
अब, चलिए अपने प्रोजेक्ट फ़ंक्शन्स बनाना शुरू करते हैं।
1. नेटवर्क पर सुझाए गए gas price को प्राप्त करना
Geth के ethclient पैकेज के साथ हम वर्तमान नेटवर्क स्थितियों के लिए उपयुक्त अपने transaction का gas price सेट करने के लिए SuggestGasPrice API का उपयोग कर सकते हैं।
बैकग्राउंड में, यह विधि (method) eth_gasPrice JSON-RPC API को कॉल करती है।
प्रोजेक्ट डायरेक्टरी में एक getGasPrice.go फ़ाइल बनाएँ और निम्नलिखित कोड पेस्ट करें:
package main
import (
"context"
"fmt"
"log"
"github.com/ethereum/go-ethereum/ethclient"
)
// getSuggestedGasPrice connects to an Ethereum node via RPC and retrieves the current suggested gas price.
func getSuggestedGasPrice(rpcUrl string) {
// Connect to the Ethereum network using the provided RPC URL.
client, err := ethclient.Dial(rpcUrl)
if err != nil {
log.Fatalf("Failed to connect to the Ethereum client: %v", err)
}
// Retrieve the currently suggested gas price for a new transaction.
gasPrice, err := client.SuggestGasPrice(context.Background())
if err != nil {
log.Fatalf("Failed to suggest gas price: %v", err)
}
// Print the suggested gas price to the terminal.
fmt.Println("Suggested Gas Price:", gasPrice.String())
}
अब main.go में main फ़ंक्शन को अपडेट करें:
func main() {
fmt.Println("using ethclient...")
getSuggestedGasPrice(sepoliaRpcUrl)
// get gas price on sepolia testnet. This was just added.
}
और चलाएँ:
go run .
हम go run main.go के बजाय go run . कमांड का उपयोग इसलिए करते हैं ताकि वर्तमान डायरेक्टरी के भीतर मौजूद उन सभी Go सोर्स फ़ाइलों को compile और execute किया जा सके जो समान पैकेज से संबंधित हैं। इसमें main.go फ़ाइल (जिसमें main फ़ंक्शन होता है) और कोई भी अन्य फ़ाइलें शामिल हैं, जैसे कि वह जिसमें हमारा getSuggestedGasPrice फ़ंक्शन शामिल है।
हम आगे चलकर इसी कमांड का उपयोग करेंगे।
कमांड चलाने के बाद, सुझाया गया gas price टर्मिनल पर प्रिंट होना चाहिए। ध्यान दें कि यह Wei में है।

2. किसी transaction के gas उपयोग का अनुमान (estimate) लगाना
ethclient में एक EstimateGas विधि भी शामिल है। यह किसी transaction को सफलतापूर्वक प्रोसेस करने के लिए आवश्यक gas की मात्रा का अनुमान लौटाता है।
EstimateGas विधि बनाए गए मैसेज को एक पैरामीटर के रूप में लेकर eth_estimateGas JSON-RPC API को कॉल करती है।
एक estimateGas.go फ़ाइल बनाएँ और निम्नलिखित कोड पेस्ट करें:
package main import (
"context"
"log"
"math/big"
"strings"
"github.com/ethereum/go-ethereum"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/ethclient"
)
// estimateGas tries to estimate the suggested amount of gas that is required to execute a given transaction.
func estimateGas(rpcUrl, from, to, data string, value uint64) uint64 {
// Establish an RPC connection to the specified RPC url
client, err := ethclient.Dial(rpcUrl)
if err != nil {
log.Fatalln(err)
}
var ctx = context.Background()
var (
fromAddr = common.HexToAddress(from) // Convert the from address from hex to an Ethereum address.
toAddr = common.HexToAddress(to) // Convert the to address from hex to an Ethereum address.
amount = new(big.Int).SetUint64(value) // Convert the value from uint64 to *big.Int.
bytesData []byte
)
// Encode the data if it's not already hex-encoded.
if data != "" {
if ok := strings.HasPrefix(data, "0x"); !ok {
data = hexutil.Encode([]byte(data))
}
bytesData, err = hexutil.Decode(data)
if err != nil {
log.Fatalln(err)
}
}
// Create a message which contains information about the transaction.
msg := ethereum.CallMsg{
From: fromAddr,
To: &toAddr,
Gas: 0x00,
Value: amount,
Data: bytesData,
}
// Estimate the gas required for the transaction.
gas, err := client.EstimateGas(ctx, msg)
if err != nil {
log.Fatalln(err)
}
return gas
}
func main() {
fmt.Println("using ethclient...")
getSuggestedGasPrice(sepoliaRpcUrl)
eGas := estimateGas(sepoliaRpcUrl, from, to, data, wei) // This was just added.
fmt.Println("\nestimate gas for the transaction is:", eGas) // This was just added.
}
go run . के साथ कोड चलाएँ
हमें यह मिलना चाहिए:

3. एक EIP1559 raw transaction बनाना
Ethereum raw transactions अपने unprocessed रूप में transactions होते हैं, जिन्हें Recursive Length Prefix (RLP) सीरियलाइजेशन विधि का उपयोग करके एनकोड किया जाता है।
इस एनकोडिंग तकनीक का उपयोग Ethereum Execution Layer (EL) द्वारा डेटा को serialize और deserialize करने के लिए किया जाता है।
raw transaction डेटा nonce, प्राप्तकर्ता का पता (to), transaction value, डेटा पेलोड (data payload), और gas limit की एनकोडिंग होती है।
Transaction के प्रकार
Ethereum के लिए मैन्युअल रूप से raw transactions बनाते समय, चुनने के लिए कई transaction प्रकार होते हैं, जो स्पष्ट gas price विनिर्देशन (specification) वाले पुराने legacy transaction (जिसे type 0 भी कहा जाता है) से लेकर EIP-1559 transactions (type 2) तक होते हैं, जो बेहतर gas price भविष्यवाणी के लिए एक base fee, एक priority fee (माइनर्स टिप), और max fee per gas पेश करता है।
base fee नेटवर्क द्वारा निर्धारित की जाती है और एक ब्लॉक के भीतर सभी transactions के लिए निश्चित (fixed) रहती है। हालाँकि, यह नेटवर्क कंजेशन के आधार पर ब्लॉक्स के बीच समायोजित (adjust) होती है। आप खनिकों (miners) को दी जाने वाली priority fee (tip) को बढ़ाकर अपने transaction की प्राथमिकता को प्रभावित कर सकते हैं।
इसके अतिरिक्त, EIP-2930 transaction (type 1) और EIP-4844 blob transactions (type 3, जिसकी चर्चा हम इस लेख में बाद में करेंगे) भी हैं।
Geth के साथ Go में transaction प्रकार चुनना
Geth क्लाइंट अपने types पैकेज के माध्यम से, इन विभिन्न transaction प्रकारों का समर्थन करता है। हमारे उद्देश्यों के लिए, हम types.DynamicFeeTx पर ध्यान केंद्रित करेंगे, जो EIP-1559 transaction मॉडल से मेल खाता है।
पूरी प्रक्रिया में कोई JSON-RPC कॉल करना शामिल नहीं है, हम बस transaction बनाते हैं, इसे sign करते हैं और इसे RLP एनकोडिंग योजना (scheme) के साथ serialize करते हैं।
एक createEIP1559RawTX.go फ़ाइल बनाएँ और निम्नलिखित कोड पेस्ट करें:
package main
import (
"bytes"
"context"
"crypto/ecdsa"
"encoding/hex"
"fmt"
"log"
"math/big"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/ethclient"
"github.com/ethereum/go-ethereum/params"
)
// createRawTransaction creates a raw EIP-1559 transaction and returns it as a hex string.
func createRawTransaction(rpcURL, to, data, privKey string, gasLimit, wei uint64) string {
// Connect to the Ethereum client using the provided RPC URL.
client, err := ethclient.Dial(rpcURL)
if err != nil {
log.Fatalln(err)
}
// Retrieve the chain ID for the target Ethereum network.
chainID, err := client.ChainID(context.Background())
if err != nil {
log.Fatalln(err)
}
// Suggest the base fee for inclusion in a block.
baseFee, err := client.SuggestGasPrice(context.Background())
if err != nil {
log.Fatalln(err)
}
// Suggest a gas tip cap (priority fee) for miner incentive.
priorityFee, err := client.SuggestGasTipCap(context.Background())
if err != nil {
log.Fatalln(err)
}
// Calculate the maximum gas fee cap, adding a 2 GWei margin to the base fee plus priority fee.
increment := new(big.Int).Mul(big.NewInt(2), big.NewInt(params.GWei))
gasFeeCap := new(big.Int).Add(baseFee, increment)
gasFeeCap.Add(gasFeeCap, priorityFee)
// Decode the provided private key.
pKeyBytes, err := hexutil.Decode("0x" + privKey)
if err != nil {
log.Fatalln(err)
}
// Convert the private key bytes to an ECDSA private key.
ecdsaPrivateKey, err := crypto.ToECDSA(pKeyBytes)
if err != nil {
log.Fatalln(err)
}
// Extract the public key from the ECDSA private key.
publicKey := ecdsaPrivateKey.Public()
publicKeyECDSA, ok := publicKey.(*ecdsa.PublicKey)
if !ok {
log.Fatal("Error casting public key to ECDSA")
}
// Compute the Ethereum address of the signer from the public key.
fromAddress := crypto.PubkeyToAddress(*publicKeyECDSA)
// Retrieve the nonce for the signer's account, representing the transaction count.
nonce, err := client.PendingNonceAt(context.Background(), fromAddress)
if err != nil {
log.Fatal(err)
}
// Prepare data payload.
var hexData string
if strings.HasPrefix(data, "0x") {
hexData = data
} else {
hexData = hexutil.Encode([]byte(data))
}
bytesData, err := hexutil.Decode(hexData)
if err != nil {
log.Fatalln(err)
}
// Set up the transaction fields, including the recipient address, value, and gas parameters.
toAddr := common.HexToAddress(to)
amount := new(big.Int).SetUint64(wei)
txData := types.DynamicFeeTx{
ChainID: chainID,
Nonce: nonce,
GasTipCap: priorityFee,
GasFeeCap: gasFeeCap,
Gas: gasLimit,
To: &toAddr,
Value: amount,
Data: bytesData,
}
// Create a new transaction object from the prepared data.
tx := types.NewTx(&txData)
// Sign the transaction with the private key of the sender.
signedTx, err := types.SignTx(tx, types.LatestSignerForChainID(chainID), ecdsaPrivateKey)
if err != nil {
log.Fatalln(err)
}
// Encode the signed transaction into RLP (Recursive Length Prefix) format for transmission.
var buf bytes.Buffer
err = signedTx.EncodeRLP(&buf)
if err != nil {
log.Fatalln(err)
}
// Return the RLP-encoded transaction as a hexadecimal string.
rawTxRLPHex := hex.EncodeToString(buf.Bytes())
return rawTxRLPHex
}
main.go में main फ़ंक्शन को अपडेट करें:
func main() {
fmt.Println("using ethclient...")
getSuggestedGasPrice(sepoliaRpcUrl)
eGas := estimateGas(sepoliaRpcUrl, from, to, data, wei) fmt.Println("\nestimate gas for the transaction is:", eGas)
rawTxRLPHex := createRawTransaction(sepoliaRpcUrl, to, data, privKey, gasLimit, wei) // This was just added.
fmt.Println("\nRaw TX:\n", rawTxRLPHex) // This was just added.
}
raw transaction ‘privKey’ वेरिएबल में संग्रहीत (stored) private key का उपयोग करके बनाया जाएगा। Sepolia टेस्टनेट पर एक सफल transaction सुनिश्चित करने के लिए, इसे (private key को) एक ऐसी private key से बदलें जिसमें टेस्ट Sepolia ETH हो।
go run . के साथ कोड चलाएँ
हमें raw transaction मिलना चाहिए, जैसा कि नीचे दिखाया गया है:

हम अगले भाग में नेटवर्क पर एक raw transaction प्रसारित (propagate) करेंगे।
4. एक raw transaction भेजना
किसी भी प्रकार का raw transaction बनाने के बाद, हम इसे ‘ethclient.SendTransaction’ फ़ंक्शन के साथ नेटवर्क पर प्रसारित कर सकते हैं, जो RLP-decoded raw transaction लेता है और eth_sendRawTransaction JSON-RPC कॉल करता है।
यहाँ कुछ जोड़ा गया कोड (Transaction struct convertHexField फ़ंक्शन) है जो अनिवार्य नहीं है लेकिन transaction के परिणाम को बेहतर ढंग से प्रिंट करने में मदद करता है।
प्रोजेक्ट में एक sendRawTX.go फ़ाइल बनाएँ और नीचे दिए गए कोड को पेस्ट करें:
package main
import (
"context"
"encoding/hex"
"encoding/json"
"fmt"
"log"
"reflect"
"strconv"
"time"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/ethclient"
"github.com/ethereum/go-ethereum/rlp"
)
// Transaction represents the structure of the transaction JSON.
type Transaction struct {
Type string `json:"type"`
ChainID string `json:"chainId"`
Nonce string `json:"nonce"`
To string `json:"to"`
Gas string `json:"gas"`
GasPrice string `json:"gasPrice,omitempty"`
MaxPriorityFeePerGas string `json:"maxPriorityFeePerGas"`
MaxFeePerGas string `json:"maxFeePerGas"` Value string `json:"value"`
Input string `json:"input"`
AccessList []string `json:"accessList"`
V string `json:"v"`
R string `json:"r"`
S string `json:"s"`
YParity string `json:"yParity"`
Hash string `json:"hash"`
TransactionTime string `json:"transactionTime,omitempty"`
TransactionCost string `json:"transactionCost,omitempty"`
}
// sendRawTransaction sends a raw Ethereum transaction.
func sendRawTransaction(rawTx, rpcURL string) {
rawTxBytes, err := hex.DecodeString(rawTx)
if err != nil {
log.Fatalln(err)
}
// Initialize an empty Transaction struct to hold the decoded data.
tx := new(types.Transaction)
// Decode the raw transaction bytes from hexadecimal to a Transaction struct.
// This step converts the RLP (Recursive Length Prefix) encoded bytes back into
// a structured Transaction format understood by the Ethereum client.
err = rlp.DecodeBytes(rawTxBytes, &tx)
if err != nil {
log.Fatalln(err)
}
// Establish an RPC connection to the specified RPC url client, err := ethclient.Dial(rpcURL)
if err != nil {
log.Fatalln(err)
}
// Propagate the transaction
err = client.SendTransaction(context.Background(), tx)
if err != nil {
log.Fatalln(err)
}
// Unmarshal the transaction JSON into a struct
var txDetails Transaction
txBytes, err := tx.MarshalJSON()
if err != nil {
log.Fatalln(err)
}
if err := json.Unmarshal(txBytes, &txDetails); err != nil {
log.Fatalln(err)
}
// Add additional transaction details
txDetails.TransactionTime = tx.Time().Format(time.RFC822)
txDetails.TransactionCost = tx.Cost().String()
// Format some hexadecimal string fields to decimal string
convertFields := []string{"Nonce", "MaxPriorityFeePerGas", "MaxFeePerGas", "Value", "Type", "Gas"}
for _, field := range convertFields {
if err := convertHexField(&txDetails, field); err != nil {
log.Fatalln(err)
}
}
// Marshal the struct back to JSON
txJSON, err := json.MarshalIndent(txDetails, "", "\t")
if err != nil {
log.Fatalln(err)
}
// Print the entire JSON with the added fields
fmt.Println("\nRaw TX Receipt:\n", string(txJSON))
}
func convertHexField(tx *Transaction, field string) error {
// Get the type of the Transaction struct
typeOfTx := reflect.TypeOf(*tx)
// Get the value of the Transaction struct
txValue := reflect.ValueOf(tx).Elem()
// Parse the hexadecimal string as an integer
hexStr := txValue.FieldByName(field).String()
intValue, err := strconv.ParseUint(hexStr[2:], 16, 64)
if err != nil {
return err
}
// Convert the integer to a decimal string
decimalStr := strconv.FormatUint(intValue, 10)
// Check if the field exists
_, ok := typeOfTx.FieldByName(field)
if !ok {
return fmt.Errorf("field %s does not exist in Transaction struct", field)
}
// Set the field value to the decimal string
txValue.FieldByName(field).SetString(decimalStr)
return nil
}
अब main.go में main फ़ंक्शन को अपडेट करें:
func main() {
fmt.Println("using ethclient...")
getSuggestedGasPrice(sepoliaRpcUrl)
eGas := estimateGas(sepoliaRpcUrl, from, to, data, wei)
fmt.Println("\nestimate gas for the transaction is:", eGas)
rawTxRLPHex := createRawTransaction(sepoliaRpcUrl, to, data, privKey, gasLimit, wei)
fmt.Println("\nRaw TX:\n", rawTxRLPHex)
sendRawTransaction(rawTxRLPHex, sepoliaRpcUrl) // This was just added.
}
go run . के साथ चलाएँ

हम ऊपर दी गई छवि (image) में transaction रसीद (receipt) देख सकते हैं
Ethereum मैसेजेस को Sign करना (digital signature)
Ethereum-signed मैसेजेस का उपयोग सत्यापन (verification) सिस्टम बनाने के लिए किया जा सकता है। यह ऑन-चेन transaction किए बिना स्वामित्व (ownership) या सहमति (consent) को सत्यापित करने का एक तरीका है।
उदाहरण के लिए, यदि User A अपनी private key के साथ एक मैसेज पर हस्ताक्षर (sign) करता है और इसे एक प्लेटफ़ॉर्म पर सबमिट करता है, तो प्लेटफ़ॉर्म उपयोगकर्ता का public address, मैसेज और signature लेता है और सत्यापित करता है कि क्या signature वास्तव में User A द्वारा किया गया था; यदि हाँ, तो यह प्लेटफ़ॉर्म के लिए कुछ करने के लिए एक प्राधिकरण (authorization) के रूप में काम कर सकता है (चाहे हस्ताक्षर करने का कारण कुछ भी हो)।
Ethereum मैसेज साइनिंग क्रिप्टोग्राफ़िक सुरक्षा के लिए secp256k1 elliptic curve digital signature algorithm (ECDSA) का उपयोग करता है।
Ethereum-signed मैसेजेस में एक prefix भी होता है, ताकि वे पहचानने योग्य हों और नेटवर्क के लिए अद्वितीय (unique) हों।
prefix है: \x19Ethereum Signed Message:\n" + len(message), और फिर हम इसे sign करने से पहले prefix+message को हैश करते हैं: sign(keccak256("\x19Ethereum Signed Message:\n" + len(message) + message)))।
Ethereum में एक recovery ID भी होता है जिसे signature के अंतिम बाइट में जोड़ा जाता है। signature 65 बाइट लंबा होता है, जिसे 3 भागों में विभाजित किया जाता है: v, r, और s। r पहले 32 बाइट्स हैं, s अगले 32 बाइट्स हैं, और v एक बाइट है जो recovery ID का प्रतिनिधित्व करता है।
Ethereum के लिए recovery ID या तो 27 (0x1b) या 28 (0x1c) होता है। आप आमतौर पर इसे सभी Ethereum digital signatures (या signed messages) के अंत में देखेंगे।
साइनिंग के लिए उपयोग किया जाने वाला Geth का crypto पैकेज recovery ID नहीं जोड़ता है जैसे कि Metamask personal_sign करता है, इसलिए हमें इसे साइन करने के बाद मैन्युअल रूप से sig[64]+=27 के साथ जोड़ना होगा जैसा कि आप नीचे दिए गए कोड में देखेंगे।
ध्यान दें कि signing messages is completely done off-chain and offline (मैसेजेस पर हस्ताक्षर करना पूरी तरह से ऑफ-चेन और ऑफलाइन किया जाता है)। यह कोई JSON-RPC कॉल नहीं करता है।
नीचे दिए गए कोड को प्रोजेक्ट डायरेक्टरी में एक ‘signMessage.go’ फ़ाइल में जोड़ें।
package mainimport (
"crypto/ecdsa"
"encoding/json"
"fmt"
"log"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/crypto"
)
// SignatureResponse represents the structure of the signature response.
type SignatureResponse struct {
Address string `json:"address,omitempty"`
Msg string `json:"msg,omitempty"`
Sig string `json:"sig,omitempty"`
Version string `json:"version,omitempty"`
}
// signMessage signs a message using the provided private key.
func signMessage(message, privKey string) (string, string) {
// Convert the private key from hex to ECDSA format
ecdsaPrivateKey, err := crypto.HexToECDSA(privKey)
if err != nil {
log.Fatalln(err)
}
// Construct the message prefix
prefix := []byte(fmt.Sprintf("\x19Ethereum Signed Message:\n%d", len(message))) messageBytes := []byte(message)
// Hash the prefix and message using Keccak-256
hash := crypto.Keccak256Hash(prefix, messageBytes)
// Sign the hashed message
sig, err := crypto.Sign(hash.Bytes(), ecdsaPrivateKey)
if err != nil {
log.Fatalln(err)
}
// Adjust signature ID to Ethereum's format
sig[64] += 27
// Derive the public key from the private key
publicKeyBytes := crypto.FromECDSAPub(ecdsaPrivateKey.Public().(*ecdsa.PublicKey))
pub, err := crypto.UnmarshalPubkey(publicKeyBytes)
if err != nil {
log.Fatal(err)
}
rAddress := crypto.PubkeyToAddress(*pub)
// Construct the signature response
res := SignatureResponse{
Address: rAddress.String(),
Msg: message,
Sig: hexutil.Encode(sig),
Version: "2", }
// Marshal the response to JSON with proper formatting
resBytes, err := json.MarshalIndent(res, " ", "\t")
if err != nil {
log.Fatalln(err)
}
return res.Sig, string(resBytes)
}
फिर से, main.go में main फ़ंक्शन को अपडेट करें:
func main() {
fmt.Println("using ethclient...")
getSuggestedGasPrice(sepoliaRpcUrl)
eGas := estimateGas(sepoliaRpcUrl, from, to, data, wei)
fmt.Println("\nestimate gas for the transaction is:", eGas)
rawTxRLPHex := createRawTransaction(sepoliaRpcUrl, to, data, privKey, gasLimit, wei)
fmt.Println("\nRaw TX:\n", rawTxRLPHex)
sendRawTransaction(rawTxRLPHex, sepoliaRpcUrl)
sig, sDetails := signMessage(data, privKey) // This was just added.
fmt.Println("\nsigned message:", sDetails) // This was just added.
}
जब आप कोड चलाएंगे तो आपको यह मिलना चाहिए:

5. Signed Ethereum मैसेजेस के signatures को Verify करना
जैसा कि पिछले भाग में बताया गया है, हम हस्ताक्षरित (signed) मैसेजेस को ऑफ़लाइन sign और verify कर सकते हैं। हस्ताक्षरित मैसेज को सत्यापित (verify) करने के लिए, हमें signature, हस्ताक्षरकर्ता (signer) का पता और मूल मैसेज की आवश्यकता होती है।
नीचे दिया गया verifySig फ़ंक्शन इन मापदंडों (parameters) को लेता है, signature को बाइट्स में डिकोड करता है, और Ethereum recovery ID को हटा देता है। इसका कारण यह है क्योंकि साइनिंग और verifying के लिए उपयोग किया जाने वाला crypto पैकेज जाँचता है कि signature की recovery ID (65वाँ बाइट) 4 से कम है (मेरा अनुमान है कि ताकि यह केवल Ethereum signatures तक सीमित न रहे)।
इसके बाद, हम आवश्यक मापदंडों को फिर से बनाते हैं (नीचे दिए गए कोड में विवरण) और crypto.Ecrecover फ़ंक्शन को कॉल करते हैं, जो EVM Ecrecover precompile contract at address (0x01) के समान काम करता है, जो उस पते को लौटाता है जिसने मैसेज पर हस्ताक्षर किए हैं (signature बनाया है)।
प्रोजेक्ट में एक verifySignedMessage.go फ़ाइल बनाएँ और यह कोड जोड़ें:
package main
import (
"fmt"
"log" "strings"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/crypto"
)
// handleVerifySig verifies the signature against the provided public key and hash.
func verifySig(signature, address, message string) bool {
// Decode the signature into bytes
sig, err := hexutil.Decode(signature)
if err != nil {
log.Fatalln(err)
}
// Adjust signature to standard format (remove Ethereum's recovery ID)
sig[64] = sig[64] - 27
// Construct the message prefix
prefix := []byte(fmt.Sprintf("\x19Ethereum Signed Message:\n%d", len(message)))
data := []byte(message)
// Hash the prefix and data using Keccak-256
hash := crypto.Keccak256Hash(prefix, data)
// Recover the public key bytes from the signature
sigPublicKeyBytes, err := crypto.Ecrecover(hash.Bytes(), sig)
if err != nil {
log.Fatalln(err)
}
ecdsaPublicKey, err := crypto.UnmarshalPubkey(sigPublicKeyBytes)
if err != nil {
log.Fatalln(err)
}
// Derive the address from the recovered public key
rAddress := crypto.PubkeyToAddress(*ecdsaPublicKey)
// Check if the recovered address matches the provided address
isSigner := strings.EqualFold(rAddress.String(), address)
return isSigner
}
main.go में main फ़ंक्शन को अपडेट करें:
func main() {
fmt.Println("using ethclient...")
getSuggestedGasPrice(sepoliaRpcUrl)
eGas := estimateGas(sepoliaRpcUrl, from, to, data, wei)
fmt.Println("\nestimate gas for the transaction is:", eGas)
rawTxRLPHex := createRawTransaction(sepoliaRpcUrl, to, data, privKey, gasLimit, wei)
fmt.Println("\nRaw TX:\n", rawTxRLPHex)
sendRawTransaction(rawTxRLPHex, sepoliaRpcUrl)
sig, sDetails := signMessage(data, privKey)
fmt.Println("\nsigned message:", sDetails)
if isSigner := verifySig(sig, from, data); isSigner { // This was just added.
fmt.Printf("\n%s signed %s\n", from, data)
} else {
fmt.Printf("\n%s did not sign %s\n", from, data)
}
}
अब हम पुष्टि कर सकते हैं कि क्या private key ने मैसेज पर हस्ताक्षर किए हैं, जो उसने किया था। चलाएँ go run .:

अभ्यास (Exercise): verifySig फ़ंक्शन में एक अलग मैसेज पास करें। आपको गलत डेटा के कारण यह मिलना चाहिए: 0x571B102323C3b8B8Afb30619Ac1d36d85359fb84 did not sign Hello Ethereum!।
6. किसी अकाउंट का nonce (transaction की संख्या) प्राप्त करना
किसी अकाउंट का nonce प्राप्त करने के लिए, हम या तो “PendingNonceAt” या “NonceAt” फ़ंक्शन का उपयोग कर सकते हैं। PendingNonceAt अकाउंट के लिए अगला अप्रयुक्त (unused) nonce लौटाता है, जबकि NonceAt अकाउंट के लिए वर्तमान nonce लौटाता है।
एक और अंतर यह है कि PendingNonceAt केवल अगला nonce प्राप्त करता है, जबकि NonceAt निर्दिष्ट ब्लॉक नंबर पर अकाउंट का nonce प्राप्त करने का प्रयास करता है; यदि कोई पास नहीं किया जाता है, तो यह अंतिम ज्ञात ब्लॉक (last known block) पर अकाउंट का nonce लौटाता है।
दोनों विधियाँ eth_getTransactionCount का उपयोग करके JSON-RPC कॉल आरंभ करती हैं; हालाँकि, पहले वाले में “pending” का दूसरा पैरामीटर शामिल है, जबकि दूसरा ब्लॉक नंबर निर्दिष्ट करता है।
अब, एक ‘getNonce.go’ फ़ाइल बनाएँ और नीचे दिए गए कोड को पेस्ट करें:
package main
import (
"context"
"fmt"
"log"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/ethclient"
)
// getNonce fetches and prints the current and next nonce for a given Ethereum address.
func getNonce(address, rpcUrl string) (uint64, uint64) {
client, err := ethclient.Dial(rpcUrl)
if err != nil {
log.Fatalln(err)
}
// Retrieve the next nonce for the address
nextNonce, err := client.PendingNonceAt(context.Background(), common.HexToAddress(address))
if err != nil {
log.Fatalln(err)
}
var currentNonce uint64 // Variable to hold the current nonce.
if nextNonce > 0 {
currentNonce = nextNonce - 1
}
return currentNonce, nextNonce
}
main फ़ंक्शन को अपडेट करें:
func main() {
fmt.Println("using ethclient...")
getSuggestedGasPrice(sepoliaRpcUrl)
eGas := estimateGas(sepoliaRpcUrl, from, to, data, wei)
fmt.Println("\nestimate gas for the transaction is:", eGas)
rawTxRLPHex := createRawTransaction(sepoliaRpcUrl, to, data, privKey, gasLimit, wei)
fmt.Println("\nRaw TX:\n", rawTxRLPHex)
sendRawTransaction(rawTxRLPHex, sepoliaRpcUrl)
sig, sDetails := signMessage(data, privKey)
fmt.Println("\nsigned message:", sDetails)
if isSigner := verifySig(sig, from, data); isSigner {
fmt.Printf("\n%s signed %s\n", from, data)
} else {
fmt.Printf("\n%s did not sign %s\n", from, data)
}
cNonce, nNonce := getNonce(to, sepoliaRpcUrl) // This was just added.
fmt.Printf("\n%s current nonce: %v\n", to, cNonce) // This was just added.
fmt.Printf("%s next nonce: %v\n", to, nNonce) // This was just added.
}
प्रोग्राम को go run . करें, आपको यह दिखाई देना चाहिए:

7. एक Transaction को Trace करना
जैसा कि पहले उल्लेख किया गया है, हम transaction tracing के लिए Geth के ‘rpc’ पैकेज का उपयोग करेंगे, एक ऐसी कार्यक्षमता जो सीधे ethclient द्वारा समर्थित नहीं है।
transactions को trace करके, हम निष्पादन पथ (execution path) की कल्पना कर सकते हैं और transaction के निष्पादन के दौरान किसी भी event logs की जानकारी प्राप्त कर सकते हैं।
इसके लिए, हम दो मुख्य विधियों पर ध्यान केंद्रित करेंगे: debug_traceTransaction और Otterscan द्वारा एक कस्टम RPC विधि ots_traceTransaction (नीचे समझाया गया है)।
debug_traceTransaction Geth की नेटिव transaction tracing का उपयोग करता है, जो transaction हैश और एक trace configuration लेता है, जो trace के प्रकार को निर्दिष्ट करता है। Geth में विभिन्न नेटिव tracers होते हैं, लेकिन हम “callTracer” का उपयोग करेंगे। सभी उपलब्ध Geth नेटिव tracers को देखने के लिए, आप बाद में दस्तावेज़ीकरण (documentation) पढ़ सकते हैं।
debug_traceTransaction Geth की अंतर्निहित (built-in) transaction tracing क्षमताओं का लाभ उठाता है। इसके लिए दो तर्कों (arguments) की आवश्यकता होती है:
-
Transaction हैश, और
-
एक trace configuration: यह trace के विवरण निर्दिष्ट करता है, जैसे कि कैप्चर की जाने वाली जानकारी का प्रकार। Geth विभिन्न नेटिव tracers प्रदान करता है, लेकिन इस उदाहरण के लिए, हम “callTracer” पर ध्यान केंद्रित करेंगे। यह tracer transaction निष्पादन के दौरान निष्पादित सभी call frames (function call) को ट्रैक करता है।
‘callTracer’ कॉन्फ़िगरेशन का उपयोग करके उत्पन्न trace का एक उदाहरण:
client.CallContext(
context.Background(),
&result,
"debug_traceTransaction",
"0xd12e31c3274ff32d5a73cc59e8deacbb0f7ac4c095385add3caa2c52d01164c1",
map[string]any{
"tracer": "callTracer",
"tracerConfig": map[string]any{"withLog": true}}
)
Transaction हैश के बाद config पैरामीटर, कनेक्टेड Geth नोड को कॉल trace करने और किसी भी उत्पन्न event logs को शामिल करने का निर्देश देता है।
हम ots_traceTransaction का उपयोग करेंगे (कोड के बाद स्पष्टीकरण देखें)।
हमारे प्रोजेक्ट में एक traceTx.go फ़ाइल बनाएँ और नीचे दिए गए कोड को पेस्ट करें:
package main
import (
"context"
"encoding/json"
"fmt"
"log"
"github.com/ethereum/go-ethereum/rpc"
)
func traceTx(hash, rpcUrl string) string {
var (
client *rpc.Client // Define a variable to hold the RPC client.
err error // Variable to catch errors.
)
// Connect to the Ethereum RPC endpoint using the provided URL.
client, err = rpc.Dial(rpcUrl)
if err != nil {
log.Fatalln(err)
}
var result json.RawMessage // Variable to hold the raw JSON result of the call.
// Make the RPC call to trace the transaction using its hash. `ots_traceTransaction` is the method name.
err = client.CallContext(context.Background(), &result, "ots_traceTransaction", hash) // or use debug_traceTransaction with a supported RPC URL and params: hash, map[string]any{"tracer": "callTracer", "tracerConfig": map[string]any{"withLog": true}} for Geth tracing
if err != nil {
log.Fatalln(err)
}
// Marshal the result into a formatted JSON string
resBytes, err := json.MarshalIndent(result, " ", "\t")
if err != nil {
log.Fatalln(err)
}
return string(resBytes))
}
main फ़ंक्शन को अपडेट करें:
func main() {
fmt.Println("using ethclient...")
getSuggestedGasPrice(sepoliaRpcUrl)
eGas := estimateGas(sepoliaRpcUrl, from, to, data, wei)
fmt.Println("\nestimate gas for the transaction is:", eGas)
rawTxRLPHex := createRawTransaction(sepoliaRpcUrl, to, data, privKey, gasLimit, wei)
fmt.Println("\nRaw TX:\n", rawTxRLPHex)
sendRawTransaction(rawTxRLPHex, sepoliaRpcUrl)
sig, sDetails := signMessage(data, privKey)
fmt.Println("\nsigned message:", sDetails)
if isSigner := verifySig(sig, from, data); isSigner {
fmt.Printf("\n%s signed %s\n", from, data) }
else {
fmt.Printf("\n%s did not sign %s\n", from, data)
}
cNonce, nNonce := getNonce(to, sepoliaRpcUrl)
fmt.Printf("\n%s current nonce: %v\n", to, cNonce)
fmt.Printf("%s next nonce: %v\n", to, nNonce)
res := traceTx("0xd12e31c3274ff32d5a73cc59e8deacbb0f7ac4c095385add3caa2c52d01164c1", mainnetRpcUrl) // This was just added.
fmt.Println("\ntrace result:\n", res) // This was just added.
}
ots_traceTransaction transaction tracing के लिए एक कस्टम Ethereum JSON-RPC विधि है जिसे Otterscan द्वारा विकसित किया गया है और यह Geth का हिस्सा नहीं है। इसके लिए इनपुट के रूप में केवल transaction हैश की आवश्यकता होती है और यह बिना किसी लॉग के एक संरचित (structured) trace आउटपुट लौटाता है।
ध्यान दें कि sepoliaRpcUrl वेरिएबल में Sepolia RPC URL ots_traceTransaction विधि का समर्थन नहीं करता है। इस उदाहरण के लिए, हम mainnetRpcUrl वेरिएबल में संग्रहीत mainnet RPC URL का उपयोग करेंगे, जो इसका समर्थन करता है।
प्रोग्राम चलाने के बाद, हमें कॉल trace दिखाई देना चाहिए।

अभ्यास (Exercise): पहले दिखाए गए callTracer कॉन्फ़िगरेशन के साथ Geth के debug_traceTransaction का उपयोग करने के लिए traceTx फ़ंक्शन को संशोधित करें। trace के लिए sepoliaRpcUrl और एक संबंधित Sepolia transaction हैश का उपयोग करें।
आपको पिछले वाले की तुलना में थोड़ा अलग trace आउटपुट दिखाई देना चाहिए जो इस तरह दिखता है:

8. EIP-4844 blob transaction बनाएँ और भेजें
Dencun हार्ड-फोर्क अभी Ethereum पर लाइव हुआ है और इसने कई EIPs पेश किए हैं, जिनमें से एक EIP-4844 है जिसमें blob transaction (type 3) नामक एक नया transaction प्रकार है।
Blobs Binary Large Objects का संक्षिप्त रूप है। Ethereum के मामले में, यह एक transaction डेटा है जो अन्य transactions की तरह execution layer पर नहीं बल्कि Ethereum की consensus layer पर बना रहता है (persist करता है)। इसलिए, आपको उन तक पहुँचने के लिए Prysm जैसे consensus क्लाइंट की आवश्यकता होती है, न कि Geth की जो एक execution क्लाइंट है।
Blob transactions फ़ील्ड
Blob transaction में EIP-1559 transaction के समान फ़ील्ड होते हैं लेकिन कुछ जोड़े गए फ़ील्ड जैसे blob_versioned_hashes (sha256 hashes का वेक्टर), और max_fee_per_blob_gas(uint256) और एक नियम है कि transaction का to फ़ील्ड शून्य (nil) नहीं होना चाहिए।
किसी blob का versioned hash जो 32 बाइट्स का होता है, शुरुआत में संस्करण (वर्तमान में 0x01, जब Ethereum पूर्ण-शार्डिंग में जाएगा तो संभवतः बदल जाएगा) का प्रतिनिधित्व करने वाले एकल बाइट से बना होता है, जिसके बाद blob की KZG प्रतिबद्धता (commitment) के SHA256 हैश के अंतिम 31 बाइट्स होते हैं (नीचे समझाया गया है)।
versioned hash
/ go-ethereum/crypto/kzg4844/kzg4844.go
// CalcBlobHashV1 calculates the 'versioned blob hash' of a commitment.
func CalcBlobHashV1(hasher hash.Hash, commit *Commitment) (vh [32]byte) {
if hasher.Size() != 32 {
panic("wrong hash size")
}
hasher.Reset()
hasher.Write(commit[:])
hasher.Sum(vh[:0]) // save the commitment hash to `vh`
vh[0] = 0x01 // set hash version
return vh
}
Blob कहाँ स्टोर होते हैं?
एक blob की पूरी सामग्री को ब्लॉक में एम्बेड नहीं किया जाता है और न ही execution layer पर रखा जाता है और EVM में पहुँचा नहीं जा सकता है, इसके बजाय सामान्य transaction निष्पादन के लिए ब्लॉक स्पेस बचाने के लिए beacon chain (consensus layer) द्वारा blob sidecars के रूप में अलग से प्रबंधित किया जाता है।
एक Sidecar में एक या blobs की एक सूची (प्रत्येक 128 बाइट्स), उनके संबंधित kzg commitment की एक सूची (प्रत्येक 48 बाइट्स) और उनके संबंधित kzg proof की एक सूची (प्रत्येक 48 बाइट्स) हो सकती है।
Blobs को 18 दिनों के लिए beacon chain में स्टोर किया जाता है और फिर उसके बाद उन्हें हटा (prune कर) दिया जाता है। Rollups blobs को स्वयं स्टोर करके या blobs को स्टोर करने के लिए p2p स्टोरेज का उपयोग करके इस समाप्ति (expiry) से निपट सकते हैं।
Blob sidecar
// go-ethereum/core/types/tx_blob.go
// BlobTxSidecar contains the blobs of a blob transaction.
type BlobTxSidecar struct {
Blobs []kzg4844.Blob // Blobs
Commitments []kzg4844.Commitment // Blob commitments
Proofs []kzg4844.Proof // Blob KZG proofs
}
blob का उपयोग KZG commitment की गणना करने के लिए किया जाता है, और blob के साथ-साथ KZG commitment का उपयोग KZG proof की गणना करने के लिए किया जाता है। इस proof का उपयोग commitment के विरुद्ध blob को सत्यापित करने के लिए किया जाता है।
Blobs का उपयोग किस लिए किया जाता है?
Blobs का मुख्य उपयोग केस layer 2s और rollups ब्लॉक डेटा को संभालना है, calldata का उपयोग करने के बजाय जिसका उपयोग उपयोगकर्ता भी करते हैं, जिससे ब्लॉक स्पेस के लिए प्रतिस्पर्धा (competition) होती है। एक अलग transaction (blobs) का उपयोग करने से layer 2s और rollups के लिए लागत कम हो जाती है।
हालाँकि, blobs केवल rollups तक सीमित नहीं हैं और किसी के द्वारा भी इसका उपयोग किया जा सकता है। मैं बाद में प्रदर्शित करूँगा कि blob transaction कैसे भेजा जाए।
प्रति transaction blob की सीमा
हम प्रति transaction एक से अधिक blob भेज सकते हैं, हालाँकि, प्रति ब्लॉक 3 का लक्ष्य (target) और अधिकतम 6 blobs की सीमा है, इसलिए तकनीकी रूप से एक blob transaction में छह blobs तक हो सकते हैं यदि यह ब्लॉक में एकमात्र blob transaction था। इसका अर्थ यह भी है कि sidecar जिसमें ये blobs होते हैं, उसमें उतने ही blob commitment और versioned hashes होंगे जितने उसमें blobs की संख्या है, इस मामले में छह।
Blob gas
Blob transactions एक अलग प्रकार के gas का उपयोग करते हैं जिसे blob gas कहा जाता है और इसके निम्नलिखित पैरामीटर होते हैं: 786,432 का MAX_BLOB_GAS_PER_BLOCK; 393,216 का TARGET_BLOB_GAS_PER_BLOCK; और 1 का MIN_BLOB_BASE_FEE।
यह उस मौजूदा transaction gas से अलग है जिसे हम जानते हैं। blob gas fee में EIP-1559 के समान मूल्य निर्धारण तंत्र है कि यह नेटवर्क कंजेशन के आधार पर बढ़ता और घटता है। यह बढ़ता है यदि पिछला ब्लॉक TARGET_BLOB_GAS_PER_BLOCK (~3 blobs) से अधिक gas का उपयोग करता है और तब घटता है जब पिछला ब्लॉक कम उपयोग करता है।
ध्यान दें कि blob versioned hashes को execution layer में blobs के संदर्भ (references) के रूप में स्टोर किया जाता है। लेकिन blobs को execution layer में स्टोर नहीं किया जाता है। Blobs को priority fee की आवश्यकता नहीं होती है क्योंकि blob डेटा निष्पादित नहीं किया जाएगा।
अंत में, Go में blob transaction बनाना एक सामान्य transaction के समान ही चरण का पालन करता है, सिवाय इसके कि हम types.BlobTx struct का उपयोग करते हैं और blob से संबंधित फ़ील्ड पास करते हैं जैसा कि पहले संकेत दिया गया था।
एक blobTx.go फ़ाइल बनाएँ और निम्नलिखित कोड पेस्ट करें:
package transaction
import (
"context"
"fmt"
"regexp"
"strings"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/crypto/kzg4844"=
"github.com/ethereum/go-ethereum/ethclient"
"github.com/holiman/uint256"
)
// SendBlobTX sends a transaction with an EIP-4844 blob payload to the Ethereum network.
func sendBlobTX(rpcURL, toAddress, data, privKey string) (string, error) {
// Connect to the Ethereum client
client, err := ethclient.Dial(rpcURL)
if err != nil {
return "", fmt.Errorf("failed to dial RPC client: %s", err)
}
defer client.Close() // Ensure the connection is closed after completing the function
// Retrieve the current chain ID
chainID, err := client.ChainID(context.Background())
if err != nil {
return "", fmt.Errorf("failed to get chain ID: %s", err)
}
var Blob [131072]byte // Define a blob array to hold the large data payload, blobs are 128kb in length
// If necessary, convert the input data to a byte slice in hex format
var bytesData []byte
if data != "" {
// Check if the data is in hex format, with or without the '0x' prefix
if IsHexWithOrWithout0xPrefix(data) {
// Ensure the data has the '0x' prefix
if !strings.HasPrefix(data, "0x") {
data = "0x" + data
}
// Decode the hex-encoded data
bytesData, err = hexutil.Decode(data)
if err != nil {
return "", fmt.Errorf("failed to decode data: %s", err)
}
// Copy the decoded data into the blob array
copy(Blob[:], bytesData)
} else {
// If the data is not in hex format, copy it directly into the blob array
copy(Blob[:], data)
}
}
// Compute the commitment for the blob data using KZG4844 cryptographic algorithm
BlobCommitment, err := kzg4844.BlobToCommitment(Blob)
if err != nil {
return "", fmt.Errorf("failed to compute blob commitment: %s", err)
}
// Compute the proof for the blob data, which will be used to verify the transaction
BlobProof, err := kzg4844.ComputeBlobProof(Blob, BlobCommitment)
if err != nil {
return "", fmt.Errorf("failed to compute blob proof: %s", err)
}
// Prepare the sidecar data for the transaction, which includes the blob and its cryptographic proof
sidecar := types.BlobTxSidecar{
Blobs: []kzg4844.Blob{Blob},
Commitments: []kzg4844.Commitment{BlobCommitment},
Proofs: []kzg4844.Proof{BlobProof},
}
// Decode the sender's private key
pKeyBytes, err := hexutil.Decode("0x" + privKey)
if err != nil {
return "", fmt.Errorf("failed to decode private key: %s", err)
}
// Convert the private key into the ECDSA format
ecdsaPrivateKey, err := crypto.ToECDSA(pKeyBytes)
if err != nil {
return "", fmt.Errorf("failed to convert private key to ECDSA: %s", err)
}
// Compute the sender's address from the public key
fromAddress := crypto.PubkeyToAddress(ecdsaPrivateKey.PublicKey)
// Retrieve the nonce for the transaction
nonce, err := client.PendingNonceAt(context.Background(), fromAddress)
fmt.Println(nonce)
if err != nil {
return "", fmt.Errorf("failed to get nonce: %s", err)
}
// Create the transaction with the blob data and cryptographic proofs
tx, err := types.NewTx(&types.BlobTx{
ChainID: uint256.MustFromBig(chainID),
Nonce: nonce,
GasTipCap: uint256.NewInt(1e10), // max priority fee per gas
GasFeeCap: uint256.NewInt(50e10), // max fee per gas
Gas: 250000, // gas limit for the transaction
To: common.HexToAddress(toAddress), // recipient's address
Value: uint256.NewInt(0), // value transferred in the transaction
Data: nil, // No additional data is sent in this transaction
BlobFeeCap: uint256.NewInt(3e10), // fee cap for the blob data
BlobHashes: sidecar.BlobHashes(), // blob hashes in the transaction
Sidecar: &sidecar, // sidecar data in the transaction
}), err
if err != nil {
return "", fmt.Errorf("failed to create transaction: %s", err)
}
// Sign the transaction with the sender's private key
signedTx, err := types.SignTx(tx, types.LatestSignerForChainID(chainID), ecdsaPrivateKey)
if err != nil {
return "", fmt.Errorf("failed to sign transaction: %s", err)
}
// Send the signed transaction to the Ethereum network
if err = client.SendTransaction(context.Background(), signedTx); err != nil {
return "", fmt.Errorf("failed to send transaction: %s", err)
}
// Return the transaction hash
txHash := signedTx.Hash().Hex()
return txHash, nil
}
// IsHexWithOrWithout0xPrefix checks if a string is hex with or without `0x` prefix using regular expression.
func IsHexWithOrWithout0xPrefix(data string) bool {
pattern := `^(0x)?[0-9a-fA-F]+$`
matched, _ := regexp.MatchString(pattern, data)
return matched
}
main फ़ंक्शन को अपडेट करें:
func main() {
fmt.Println("using ethclient...")
getSuggestedGasPrice(sepoliaRpcUrl)
eGas := estimateGas(sepoliaRpcUrl, from, to, data, wei)
fmt.Println("\nestimate gas for the transaction is:", eGas)
rawTxRLPHex := createRawTransaction(sepoliaRpcUrl, to, data, privKey, gasLimit, wei)
fmt.Println("\nRaw TX:\n", rawTxRLPHex) sendRawTransaction(rawTxRLPHex, sepoliaRpcUrl)
sig, sDetails := signMessage(data, privKey)
fmt.Println("\nsigned message:", sDetails)
if isSigner := verifySig(sig, from, data); isSigner {
fmt.Printf("\n%s signed %s\n", from, data)
} else {
fmt.Printf("\n%s did not sign %s\n", from, data)
}
cNonce, nNonce := getNonce(to, sepoliaRpcUrl)
fmt.Printf("\n%s current nonce: %v\n", to, cNonce)
fmt.Printf("%s next nonce: %v\n", to, nNonce)
res := traceTx("0xd12e31c3274ff32d5a73cc59e8deacbb0f7ac4c095385add3caa2c52d01164c1", mainnetRpcUrl)
fmt.Println("\ntrace result:\n", res)
blob, err := sendBlobTX(sepoliaRpcUrl, to, data, privKey) // This was just added.
if err != nil {
log.Fatalln(err)
}
fmt.Println("\nBlob transaction hash:", blob) // This was just added.
}
हमारे प्रोग्राम को चलाने से पहले, अस्थायी रूप से sendRawTransaction और traceTx फ़ंक्शन कॉल को कमेंट आउट कर दें। ऐसा इसलिए है क्योंकि sendRawTransaction से लंबित (pending) transaction blob transaction बनाते समय nonce संघर्ष (nonce gap त्रुटि) का कारण बन सकता है, और बाद में traceTx कॉल टर्मिनल आउटपुट को अव्यवस्थित (clutter) कर देगा।
ऐसा करने के बाद, go run . के साथ चलाएँ। आपको transaction हैश मिल जाना चाहिए।

आप इसे Etherscan पर देख सकते हैं, यहाँ वह है जो मैंने बनाया है:
सारांश
Go-Ethereum (Geth) ethclient पैकेज Ethereum के साथ कई सामान्य इंटरैक्शन को सरल बनाता है। हालाँकि, वहाँ मौजूद हर दूसरे क्लाइंट की तरह, यह सभी Ethereum JSON-RPC APIs के लिए विधियाँ प्रदान नहीं करता है, जैसा कि हमने transaction tracing के साथ देखा है। ऐसे मामलों में, मैन्युअल रूप से JSON-RPC कॉल का निर्माण करना आवश्यक है। सौभाग्य से, Geth rpc पैकेज Go डेवलपर्स के लिए इसे आसान बनाता है।
मूल रूप से 3 अप्रैल, 2024 को प्रकाशित