Skip to content

Commit

Permalink
feat: add arweave client
Browse files Browse the repository at this point in the history
  • Loading branch information
pseudoyu committed Nov 20, 2023
1 parent 0142dbb commit 60ba32e
Show file tree
Hide file tree
Showing 11 changed files with 709 additions and 3 deletions.
10 changes: 9 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ go 1.21
require (
github.com/avast/retry-go/v4 v4.5.1
github.com/ethereum/go-ethereum v1.13.5
github.com/hamba/avro/v2 v2.18.0
github.com/labstack/gommon v0.4.1
github.com/samber/lo v1.38.1
github.com/shopspring/decimal v1.3.1
github.com/sourcegraph/conc v0.3.0
Expand Down Expand Up @@ -33,10 +35,14 @@ require (
github.com/hashicorp/hcl v1.0.0 // indirect
github.com/holiman/uint256 v1.2.3 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/magiconair/properties v1.8.7 // indirect
github.com/mattn/go-isatty v0.0.19 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect
github.com/mmcloughlin/addchain v0.4.0 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/pelletier/go-toml/v2 v2.1.0 // indirect
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
github.com/sagikazarmark/locafero v0.3.0 // indirect
Expand All @@ -49,6 +55,8 @@ require (
github.com/supranational/blst v0.3.11 // indirect
github.com/tklauser/go-sysconf v0.3.12 // indirect
github.com/tklauser/numcpus v0.6.1 // indirect
github.com/valyala/bytebufferpool v1.0.0 // indirect
github.com/valyala/fasttemplate v1.2.2 // indirect
go.uber.org/multierr v1.11.0 // indirect
golang.org/x/crypto v0.15.0 // indirect
golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa // indirect
Expand Down
23 changes: 21 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,7 @@ github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
Expand All @@ -192,6 +193,8 @@ github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5m
github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g=
github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc=
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/hamba/avro/v2 v2.18.0 h1:U7T0xI8MGw9+m3SS48E2KHUxas/Hb0EvS0CpkmVcLoI=
github.com/hamba/avro/v2 v2.18.0/go.mod h1:dEG+AHrykTpkXvBYsc+XXTuRlvGC645Ix5d2qR8EdEs=
github.com/hashicorp/go-bexpr v0.1.10 h1:9kuI5PFotCboP3dkDYFr/wi0gg0QVbSNz5oFRpxn4uE=
github.com/hashicorp/go-bexpr v0.1.10/go.mod h1:oxlubA2vC/gFVfX1A6JGp7ls7uCDlfJn732ehYYg+g0=
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
Expand All @@ -212,6 +215,8 @@ github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
github.com/jackpal/go-nat-pmp v1.0.2 h1:KzKSgb7qkJvOUTqYl9/Hg/me3pWgBmERKrTGD7BdWus=
github.com/jackpal/go-nat-pmp v1.0.2/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc=
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
Expand All @@ -227,14 +232,17 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
github.com/labstack/gommon v0.4.1 h1:gqEff0p/hTENGMABzezPoPSRtIh1Cvw0ueMOe0/dfOk=
github.com/labstack/gommon v0.4.1/go.mod h1:TyTrpPqxR5KMk8LKVtLmfMjeQ5FEkBYdxLYPw/WfrOM=
github.com/leanovate/gopter v0.2.9 h1:fQjYxZaynp97ozCzfOyOuAGOU4aU/z37zf/tOujFk7c=
github.com/leanovate/gopter v0.2.9/go.mod h1:U2L/78B+KVFIx2VmW6onHJQzXtFb+p5y3y2Sh+Jxxv8=
github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY=
github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA=
github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mattn/go-runewidth v0.0.13 h1:lTGmDsbAYt5DmK6OnoV7EuIF1wEIFAcxld6ypU4OSgU=
github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 h1:I0XW9+e1XWDxdcEniV4rQAIOPUGDq67JSCiRCgGCZLI=
Expand All @@ -246,6 +254,11 @@ github.com/mitchellh/pointerstructure v1.2.0/go.mod h1:BRAsLI5zgXmw97Lf6s25bs8oh
github.com/mmcloughlin/addchain v0.4.0 h1:SobOdjm2xLj1KkXN5/n0xTIWyZA2+s99UCY1iPfkHRY=
github.com/mmcloughlin/addchain v0.4.0/go.mod h1:A86O+tHqZLMNO4w6ZZ4FlVQEadcoqkyU72HC5wJ4RlU=
github.com/mmcloughlin/profile v0.1.1/go.mod h1:IhHD7q1ooxgwTgjxQYkACGA77oFTDdFVejUS1/tS/qU=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec=
github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY=
github.com/pelletier/go-toml/v2 v2.1.0 h1:FnwAJ4oYMvbT/34k9zzHuZNrhlz48GB3/s6at6/MHO4=
Expand Down Expand Up @@ -301,6 +314,7 @@ github.com/status-im/keycard-go v0.2.0/go.mod h1:wlp8ZLbsmrF6g6WjugPAx+IzoLrkdf9
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
Expand All @@ -322,6 +336,10 @@ github.com/tyler-smith/go-bip39 v1.1.0 h1:5eUemwrMargf3BSLRRCalXT93Ns6pQJIjYQN2n
github.com/tyler-smith/go-bip39 v1.1.0/go.mod h1:gUYDtqQw1JS3ZJ8UWVcGTGqqr6YIN3CWg+kkNaLt55U=
github.com/urfave/cli/v2 v2.25.7 h1:VAzn5oq403l5pHjc4OhD54+XGO9cdKVL/7lDjF+iKUs=
github.com/urfave/cli/v2 v2.25.7/go.mod h1:8qnjx1vcq5s2/wpsqoZFndg2CE5tNFyrTvS6SinrnYQ=
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
github.com/valyala/fasttemplate v1.2.2 h1:lxLXG0uE3Qnshl9QyaK6XJxMXlQZELvChBOCmQD0Loo=
github.com/valyala/fasttemplate v1.2.2/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ=
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 h1:bAn7/zixMGCfxrRTfdpNzjtPYqr8smhKouy9mxVdGPU=
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8=
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
Expand Down Expand Up @@ -475,6 +493,7 @@ golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
Expand Down
238 changes: 238 additions & 0 deletions provider/arweave/bundle/bundle.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,238 @@
package bundle

import (
"encoding/base64"
"encoding/binary"
"fmt"
"io"

"github.com/hamba/avro/v2"
"github.com/samber/lo"
)

type Decoder struct {
reader io.Reader
buffer io.Reader
schema avro.Schema
header Header
cursor uint32
}

func (d *Decoder) DecodeHeader() (*Header, error) {
if err := d.decodeHeaderDataItemNumbers(); err != nil {
return nil, fmt.Errorf("decode data item numbers: %w", err)
}

if err := d.decodeHeaderDataInfos(); err != nil {
return nil, fmt.Errorf("decode data infos: %w", err)
}

header := d.header

return &header, nil
}

func (d *Decoder) DecodeDataItem() (*DataItem, error) {
dataItemInfo := d.header.DataItemInfos[d.cursor]

d.buffer = io.LimitReader(d.reader, int64(dataItemInfo.Size))

var dataItem DataItem

if err := d.decodeDataItemSignature(&dataItem); err != nil {
return nil, fmt.Errorf("decode data item info signature: %w", err)
}

if err := d.decodeDataItemOwner(&dataItem); err != nil {
return nil, fmt.Errorf("decode data item info owner: %w", err)
}

if err := d.decodeDataItemTarget(&dataItem); err != nil {
return nil, fmt.Errorf("decode data item info target: %w", err)
}

if err := d.decodeDataItemAnchor(&dataItem); err != nil {
return nil, fmt.Errorf("decode data item info anchor: %w", err)
}

if err := d.decodeDataItemTags(&dataItem); err != nil {
return nil, fmt.Errorf("decode data item info tags: %w", err)
}

dataItem.dataReader = d.buffer

d.cursor++

return &dataItem, nil
}

func (d *Decoder) Next() bool {
return d.cursor < d.header.Numbers
}

func (d *Decoder) decodeHeaderDataItemNumbers() error {
buffer := make([]byte, 32)

_, err := io.ReadFull(d.reader, buffer)
if err != nil {
return err
}

d.header.Numbers = binary.LittleEndian.Uint32(buffer)

return nil
}

func (d *Decoder) decodeHeaderDataInfos() error {
d.header.DataItemInfos = make([]DataItemInfo, 0, d.header.Numbers)

buffer := make([]byte, 64)

for index := uint32(0); index < d.header.Numbers; index++ {
if _, err := io.ReadFull(d.reader, buffer); err != nil {
return err
}

dataItemInfo := DataItemInfo{
Size: binary.LittleEndian.Uint32(buffer[:32]),
ID: base64.RawURLEncoding.EncodeToString(buffer[32:]),
}

d.header.DataItemInfos = append(d.header.DataItemInfos, dataItemInfo)
}

return nil
}

func (d *Decoder) decodeDataItemSignature(dataItem *DataItem) error {
buffer := make([]byte, 2)

if _, err := io.ReadFull(d.buffer, buffer); err != nil {
return err
}

dataItem.SignatureType = binary.LittleEndian.Uint16(buffer)

signatureType, supported := d.lookupDataItemSignatureType(dataItem)
if !supported {
return fmt.Errorf("unsupported signature type: %d", dataItem.SignatureType)
}

buffer = make([]byte, signatureType.SignatureLength)

if _, err := io.ReadFull(d.buffer, buffer); err != nil {
return err
}

dataItem.Signature = base64.RawURLEncoding.EncodeToString(buffer)

return nil
}

func (d *Decoder) decodeDataItemOwner(dataItem *DataItem) error {
var buffer []byte

signatureType, supported := d.lookupDataItemSignatureType(dataItem)
if !supported {
return fmt.Errorf("unsupported signature type: %d", dataItem.SignatureType)
}

buffer = make([]byte, signatureType.PublicKeyLength)

if _, err := io.ReadFull(d.buffer, buffer); err != nil {
return err
}

dataItem.Owner = base64.RawURLEncoding.EncodeToString(buffer)

return nil
}

func (d *Decoder) decodeDataItemPresenceField(buffer []byte) (bool, error) {
if _, err := io.ReadFull(d.buffer, buffer[:1]); err != nil {
return false, err
}

switch flag := buffer[0]; flag {
case 0x0:
return false, nil
case 0x1:
_, err := io.ReadFull(d.buffer, buffer[1:])

return true, err
default:
return false, fmt.Errorf("invalid presence byte: %d", flag)
}
}

func (d *Decoder) decodeDataItemTarget(dataItem *DataItem) error {
buffer := make([]byte, 32+1)

presence, err := d.decodeDataItemPresenceField(buffer)
if err != nil {
return err
}

if presence {
dataItem.Target = base64.RawURLEncoding.EncodeToString(buffer[1:])
}

return nil
}

func (d *Decoder) decodeDataItemAnchor(dataItem *DataItem) error {
buffer := make([]byte, 32+1)

presence, err := d.decodeDataItemPresenceField(buffer)
if err != nil {
return err
}

if presence {
dataItem.Anchor = base64.RawURLEncoding.EncodeToString(buffer[1:])
}

return nil
}

func (d *Decoder) decodeDataItemTags(dataItem *DataItem) error {
buffer := make([]byte, 8)

if _, err := io.ReadFull(d.buffer, buffer); err != nil {
return err
}

dataItem.TagsNumber = binary.LittleEndian.Uint16(buffer)

if _, err := io.ReadFull(d.buffer, buffer); err != nil {
return err
}

dataItem.TagsBytes = binary.LittleEndian.Uint16(buffer)

buffer = make([]byte, dataItem.TagsBytes)

if _, err := io.ReadFull(d.buffer, buffer); err != nil {
return err
}

return avro.Unmarshal(d.schema, buffer, &dataItem.Tags)
}

func (d *Decoder) lookupDataItemSignatureType(dataItem *DataItem) (*SignatureType, bool) {
signatureType, exist := signatureTypeMap[dataItem.SignatureType]
if !exist {
return nil, false
}

return &signatureType, true
}

func NewDecoder(reader io.Reader) *Decoder {
decoder := Decoder{
reader: reader,
schema: lo.Must(avro.Parse(`{"type":"array","items":{"type":"record","name":"Tag","fields":[{"name":"name","type":"bytes"},{"name":"value","type":"bytes"}]}}`)),
}

return &decoder
}
Loading

0 comments on commit 60ba32e

Please sign in to comment.