Created
July 17, 2025 14:40
-
-
Save csknk/d494abc86194ec6d17000aff80fead42 to your computer and use it in GitHub Desktop.
Go Challenge Solana Encoding
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"bytes" | |
"crypto/sha256" | |
"encoding/binary" | |
"encoding/hex" | |
"fmt" | |
"strings" | |
) | |
var ( | |
discriminator = MustUnhex("e445a52e51cb9a1d") | |
eventDiscriminator = getEventDiscriminator("PacketSentEvent") // 005ca7c98b2eab52 | |
) | |
func getEventDiscriminator(evtName string) []byte { | |
payload := fmt.Appendf(nil, "event:%s", evtName) | |
return sha256hash(payload)[0:8] | |
} | |
func MustUnhex(hexString string) []byte { | |
// More concise, improves readability without changing behaviour | |
hexString = strings.TrimPrefix(hexString, "0x") | |
h, err := hex.DecodeString(hexString) | |
if err != nil { | |
panic(err) | |
} | |
return h | |
} | |
func sha256hash(data ...[]byte) []byte { | |
h := sha256.New() | |
for _, d := range data { | |
h.Write(d) | |
} | |
return h.Sum(nil) | |
} | |
type PacketSentEvent struct { | |
EncodedPayload []byte | |
Options []byte | |
SendLibrary []byte | |
} | |
type InstructionData []byte | |
func (data InstructionData) IsPacketSentEvent() bool { | |
// should probalby include some guards here: check data is not nil, and has the sufficient length... | |
if bytes.Equal(data[:8], discriminator) && bytes.Equal(data[8:16], eventDiscriminator) { | |
return true | |
} | |
return false | |
} | |
// ExtractPacketSentEvent -- | |
// After some experimentation it appears that the data we are trying to unpack is structured | |
// like this: [u32 length][EncodedPayload][u32 length][Options][SendLibrary - fixed length, 32 bytes] | |
func (data InstructionData) ExtractPacketSentEvent() (PacketSentEvent, error) { | |
buf := bytes.NewReader(data[16:]) | |
readBytes := func() ([]byte, error) { | |
var length uint32 | |
// read the length variable which denotes the size of the following field | |
if err := binary.Read(buf, binary.LittleEndian, &length); err != nil { | |
return nil, err | |
} | |
bytes := make([]byte, length) | |
// read the required n bytes from the buffer | |
if _, err := buf.Read(bytes); err != nil { | |
return nil, err | |
} | |
return bytes, nil | |
} | |
encodedPayload, err := readBytes() | |
if err != nil { | |
return PacketSentEvent{}, fmt.Errorf("reading EncodedPayload: %w", err) | |
} | |
options, err := readBytes() | |
if err != nil { | |
return PacketSentEvent{}, fmt.Errorf("reading Options: %w", err) | |
} | |
// Looks like the SendLibrary field has fixed-size: 32 bytes | |
// cursor is at the correct offset, so just read the bytes | |
sendLibrary := make([]byte, 32) | |
if _, err := buf.Read(sendLibrary); err != nil { | |
return PacketSentEvent{}, fmt.Errorf("reading SendLibrary: %w", err) | |
} | |
return PacketSentEvent{ | |
EncodedPayload: encodedPayload, | |
Options: options, | |
SendLibrary: sendLibrary, | |
}, nil | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment