Untitled

3 min read Original article ↗
package main import ( "bytes" "crypto/sha256" "encoding/binary" "encoding/hex" "fmt" "io" "net" "strings" "time" ) const ( Magic uint32 = 0xD9B4BEF9 ProtocolVersion uint32 = 70017 ServerAddress = "127.0.0.1:8333" MaxHeadersToSend = 1999 ) func main() { fmt.Println("\n ┓ • • bigpiang by Kevin McSheehan (pad)") fmt.Println(" ┣┓┓╋┏┓┓┏┓┏┓┏┓ Disclaimer: Benchmark machines that you own.") fmt.Println(" ┗┛┗┗┣┛┗┗┻┛┗┗┫ x.com/123456\n") var numGoroutines int fmt.Print("Enter the number of goroutines: ") fmt.Scanln(&numGoroutines) var benchmarkType string fmt.Print("Enter the benchmark type (headers/ping): ") fmt.Scanln(&benchmarkType) for i := 0; i < numGoroutines; i++ { if benchmarkType == "headers" { go processBlocks(i) } else if benchmarkType == "ping" { go sendPings(i) } else { fmt.Println("Invalid benchmark type. Exiting.") return } } select {} } func sendPings(threadNum int) { conn := connectAndHandshake() fmt.Printf("Now benchmarking %s...\n", ServerAddress) for { if err := sendMessage(conn, "ping", nil); err != nil { conn = connectAndHandshake() } } } func processBlocks(threadNum int) { startHash := "0000000000000000000000000000000000000000000000000000000000000000" stopHash := "0000000000000000000000000000000000000000000000000000000000000000" conn := connectAndHandshake() fmt.Printf("Now benchmarking %s...\n", ServerAddress) for { if err := requestBlockHeaders(conn, startHash, stopHash); err != nil { conn = connectAndHandshake() } } } func requestBlockHeaders(conn net.Conn, startHash, stopHash string) error { payload := createGetHeadersPayload(startHash, stopHash) if err := sendMessage(conn, "getheaders", payload); err != nil { return err } for { command, _, err := receiveMessage(conn) if err != nil { return err } if command == "headers" { break } } return nil } func connectAndHandshake() net.Conn { var conn net.Conn var err error for { conn, err = net.Dial("tcp", ServerAddress) if err == nil { if err = handshake(conn); err == nil { break } } } return conn } func handshake(conn net.Conn) error { if err := sendMessage(conn, "version", createVersionPayload()); err != nil { return err } handshakeCompleted := false for !handshakeCompleted { command, _, err := receiveMessage(conn) if err != nil { return err } switch command { case "version": if err := sendMessage(conn, "verack", nil); err != nil { return err } case "verack": handshakeCompleted = true } } return nil } func sendMessage(conn net.Conn, command string, payload []byte) error { _, err := conn.Write(packCommand(command, payload)) return err } func receiveMessage(conn net.Conn) (string, []byte, error) { header := make([]byte, 24) if _, err := io.ReadFull(conn, header); err != nil { return "", nil, err } length := binary.LittleEndian.Uint32(header[16:20]) command := strings.TrimRight(string(header[4:16]), "\x00") payload := make([]byte, length) if length > 0 { if _, err := io.ReadFull(conn, payload); err != nil { return "", nil, err } firstSHA := sha256.Sum256(payload) checksum := sha256.Sum256(firstSHA[:]) if !bytes.Equal(checksum[:4], header[20:24]) { return "", nil, fmt.Errorf("invalid checksum") } } return command, payload, nil } func packCommand(command string, payload []byte) []byte { var cmd [12]byte copy(cmd[:], command) firstSHA := sha256.Sum256(payload) checksum := sha256.Sum256(firstSHA[:]) packet := make([]byte, 24+len(payload)) binary.LittleEndian.PutUint32(packet[0:4], Magic) copy(packet[4:16], cmd[:]) binary.LittleEndian.PutUint32(packet[16:20], uint32(len(payload))) copy(packet[20:24], checksum[:4]) copy(packet[24:], payload) return packet } func createVersionPayload() []byte { var addr [26]byte binary.LittleEndian.PutUint64(addr[:8], 1) payload := make([]byte, 85) binary.LittleEndian.PutUint32(payload, ProtocolVersion) binary.LittleEndian.PutUint64(payload[4:12], uint64(time.Now().Unix())) copy(payload[12:38], addr[:]) copy(payload[38:64], addr[:]) binary.LittleEndian.PutUint64(payload[64:72], 0) copy(payload[72:80], []byte("/golang-client:0.0.1/")) binary.LittleEndian.PutUint32(payload[80:84], 0) payload[84] = 0 return payload } func createGetHeadersPayload(startHash, stopHash string) []byte { startHashBytes, _ := hex.DecodeString(startHash) stopHashBytes, _ := hex.DecodeString(stopHash) reverseBytes(startHashBytes) reverseBytes(stopHashBytes) payload := make([]byte, 2+4+32+32) binary.LittleEndian.PutUint16(payload[0:2], MaxHeadersToSend) binary.LittleEndian.PutUint32(payload[2:6], ProtocolVersion) copy(payload[6:38], startHashBytes) copy(payload[38:70], stopHashBytes) return payload } func reverseBytes(b []byte) { for i := len(b)/2 - 1; i >= 0; i-- { opp := len(b) - 1 - i b[i], b[opp] = b[opp], b[i] } }