Skip to content

Commit

Permalink
Msgpack encoding (KyberNetwork#472)
Browse files Browse the repository at this point in the history
* using KyberNetwork/msgpack/v5

* encoding test

encoding test

renamed

* feat: handled uniswapentities.{Token, Native, Ether} cycle pointer alias
feat: added generate_register_pool_types.go to automatically msgpack.RegisterConcreteType() for all PoolSimulator
feat: implemented AfterMsgpackUnmarshal() for pools that need to set pointer alias after decoding

* Revert "encoding test"

This reverts commit 9858b05.

* removed test

* rerun go generate

* added go_generate_check.yaml

* update README.md

* ignore `go generate ./...` exit code

* update go_generate_check.yaml's name
  • Loading branch information
phqb authored Jun 13, 2024
1 parent adf5987 commit b2951e2
Show file tree
Hide file tree
Showing 30 changed files with 965 additions and 11 deletions.
29 changes: 29 additions & 0 deletions .github/workflows/go_generate_check.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
name: Check generated codes update-to-date

concurrency:
group: ci-workflow-${{ github.ref }}-${{ github.event_name }}
cancel-in-progress: true

on:
workflow_dispatch:
push:
branches:
- main
- release-v**
pull_request:

jobs:
generate-check:
name: Check generated codes update-to-date
runs-on: [ubuntu-22.04]
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Install Go
uses: actions/setup-go@v5
with:
go-version-file: 'go.mod'
- name: Run "go generate ./..."
run: go generate ./... || true
- name: Check working tree clean
run: if [ -z "$(git status --porcelain)" ]; then exit 0; else exit 1; fi
27 changes: 27 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1 +1,28 @@
# kyberswap-dex-lib

## Marshal/unmarshal pool simulator

When implementing a new pool simulator, to make it marshal-able and unmarshal-able, we have to notice the following:

* rerun `go generate ./...` to register the new pool simulator struct
* Because we might marshal/unmarshal a pool simulator under the `IPoolSimulator` interface. We have to register the underlying struct so we can unmarshal it as `IPoolSimulator`.

* pointer aliases
* If the pool simulator struct contains pointer aliases, we must use `msgpack:"-"` tag to ignore the aliases and set them inside the `AfterMsgpackUnmarshal()` method. For an example:
```
type PoolSimulator struct {
vault *Vault
vaultUtils *VaultUtils
}

type VaultUtils struct {
vault *Vault `msgpack:"-"`
}

func (p *PoolSimulator) AfterMsgpackUnmarshal() error {
if p.vaultUtils != nil {
p.vaultUtils.vault = p.vault
}
return nil
}
```
5 changes: 5 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ require (
github.com/KyberNetwork/iZiSwap-SDK-go v1.1.0
github.com/KyberNetwork/int256 v0.1.4
github.com/KyberNetwork/logger v0.1.0
github.com/KyberNetwork/msgpack/v5 v5.4.2
github.com/KyberNetwork/pancake-v3-sdk v0.2.0
github.com/KyberNetwork/uniswapv3-sdk-uint256 v0.5.0
github.com/daoleno/uniswap-sdk-core v0.1.7
Expand All @@ -20,6 +21,7 @@ require (
github.com/go-resty/resty/v2 v2.10.0
github.com/goccy/go-json v0.10.2
github.com/golang/mock v1.6.0
github.com/google/go-cmp v0.5.9
github.com/holiman/uint256 v1.2.4
github.com/machinebox/graphql v0.2.2
github.com/mitchellh/mapstructure v1.4.1
Expand All @@ -32,6 +34,8 @@ require (
golang.org/x/sync v0.5.0
)

require github.com/klauspost/compress v1.17.8

require (
github.com/Microsoft/go-winio v0.6.1 // indirect
github.com/bits-and-blooms/bitset v1.11.0 // indirect
Expand All @@ -56,6 +60,7 @@ 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/vmihailenco/tagparser/v2 v2.0.0 // indirect
github.com/yusufpapurcu/wmi v1.2.3 // indirect
go.uber.org/multierr v1.11.0 // indirect
go.uber.org/zap v1.26.0 // indirect
Expand Down
10 changes: 8 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ github.com/KyberNetwork/int256 v0.1.4 h1:SbnhxqcsZXrP+5pSkolpSo2ViEWiq3K/hjfl5OQ
github.com/KyberNetwork/int256 v0.1.4/go.mod h1:qE/Ikpo86fn60sIB7CwcfiqJTjK2p+k+ASvuO79Rq4g=
github.com/KyberNetwork/logger v0.1.0 h1:Iibu9Ls+tipjR+C0iXhzUYM1VtRgmmR1HHWGufPYcbs=
github.com/KyberNetwork/logger v0.1.0/go.mod h1:zBqHbtJ3nJn6HQnp6UW8pbQkR+U6tSRFd5CzfiKL3Kw=
github.com/KyberNetwork/msgpack/v5 v5.4.2 h1:1RBX5AriCTNnXheBzV3/upOPr8QxjdGDSY1RQBPtnvM=
github.com/KyberNetwork/msgpack/v5 v5.4.2/go.mod h1:91PLIDmaoFsGuwQHhXDU8hv7JKubN2seUhUMbj9kXmM=
github.com/KyberNetwork/pancake-v3-sdk v0.2.0 h1:dd5k2Z223kkzSky8SFgRy2/eQGp4bf586SS71XqqBlM=
github.com/KyberNetwork/pancake-v3-sdk v0.2.0/go.mod h1:AhHu1v2KZAXKFZ9AnjwYPPx1+dDFHBqmSpSeg4fnvzg=
github.com/KyberNetwork/uniswapv3-sdk v0.5.0 h1:Akl6KR27K+gVMOf9x9u9dV32j9YTIEnY99R9z+WlVGI=
Expand Down Expand Up @@ -109,6 +111,8 @@ github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb h1:PBC98N2aIaM3XXiurYmW7fx4GZkL8feAMVq7nEjURHk=
github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
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.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/subcommands v1.2.0/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk=
Expand All @@ -128,8 +132,8 @@ github.com/huin/goupnp v1.3.0 h1:UvLUlWDNpoUdYzb2TCn+MuTWtcjXKSza2n6CBdQ0xXc=
github.com/huin/goupnp v1.3.0/go.mod h1:gnGPsThkYa7bFi/KWmEysQRf48l2dvR5bxr2OFckNX8=
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/klauspost/compress v1.15.15 h1:EF27CXIuDsYJ6mmvtBRlEuB2UVOqHG1tAXgZ7yIO+lw=
github.com/klauspost/compress v1.15.15/go.mod h1:ZcK2JAFqKOpnBlxcLsJzYfrS9X1akm9fHZNnD9+Vo/4=
github.com/klauspost/compress v1.17.8 h1:YcnTYrq7MikUT7k0Yb5eceMmALQPYBW/Xltxn0NAMnU=
github.com/klauspost/compress v1.17.8/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
Expand Down Expand Up @@ -210,6 +214,8 @@ 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/vmihailenco/tagparser/v2 v2.0.0 h1:y09buUbR+b5aycVFQs/g70pqKVZNBmxwAhO7/IwNM9g=
github.com/vmihailenco/tagparser/v2 v2.0.0/go.mod h1:Wri+At7QHww0WTrCBeu4J6bNtoV6mEfg5OIWRZA9qds=
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.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
Expand Down
42 changes: 42 additions & 0 deletions pkg/msgpack/decoder.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package msgpack

import (
"bytes"
"io"
"sync"

"github.com/KyberNetwork/kyberswap-dex-lib/pkg/source/pool"
"github.com/KyberNetwork/msgpack/v5"
"github.com/klauspost/compress/snappy"
)

var decoderPool = sync.Pool{
New: func() any {
de := msgpack.NewDecoder(nil)
return de
},
}

func NewDecoder(r io.Reader) *msgpack.Decoder {
de := decoderPool.Get().(*msgpack.Decoder)
de.Reset(r)
de.IncludeUnexported(true)
de.SetForceAsArray(true)
return de
}

func PutDecoder(en *msgpack.Decoder) {
decoderPool.Put(en)
}

// DecodePoolSimulatorsMap decodes an encoded and Snappy compressed map from pool ID to IPoolSimulator
func DecodePoolSimulatorsMap(encoded []byte) (map[string]pool.IPoolSimulator, error) {
poolsMap := make(map[string]pool.IPoolSimulator)
zw := snappy.NewReader(bytes.NewReader(encoded))
de := NewDecoder(zw)
defer PutDecoder(de)
if err := de.Decode(&poolsMap); err != nil {
return nil, err
}
return poolsMap, nil
}
47 changes: 47 additions & 0 deletions pkg/msgpack/encoder.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package msgpack

import (
"bytes"
"io"
"sync"

"github.com/KyberNetwork/kyberswap-dex-lib/pkg/source/pool"
"github.com/KyberNetwork/msgpack/v5"
"github.com/klauspost/compress/snappy"
)

var encoderPool = sync.Pool{
New: func() any {
en := msgpack.NewEncoder(nil)
return en
},
}

func NewEncoder(w io.Writer) *msgpack.Encoder {
en := encoderPool.Get().(*msgpack.Encoder)
en.Reset(w)
en.IncludeUnexported(true)
en.SetForceAsArray(true)
return en
}

func PutEncoder(en *msgpack.Encoder) {
encoderPool.Put(en)
}

// EncodePoolSimulatorsMap encode a map from pool ID to IPoolSimulator with Snappy compression
func EncodePoolSimulatorsMap(poolsMap map[string]pool.IPoolSimulator) ([]byte, error) {
var (
buf bytes.Buffer
zw = snappy.NewBufferedWriter(&buf)
)
en := NewEncoder(zw)
defer PutEncoder(en)
if err := en.Encode(poolsMap); err != nil {
return nil, err
}
if err := zw.Close(); err != nil {
return nil, err
}
return buf.Bytes(), nil
}
168 changes: 168 additions & 0 deletions pkg/msgpack/generate/generate_register_pool_types.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
package main

import (
"bufio"
"fmt"
"io"
"io/fs"
"log"
"os"
"path/filepath"
"strings"
)

const (
poolSimFileName = "pool_simulator.go"
moduleName = "github.com/KyberNetwork/kyberswap-dex-lib"
regularPoolSimName = "PoolSimulator"
)

var (
irregularPoolSimNameByPackageName = map[string]string{
"pkg_source_balancer_stable": "StablePool",
"pkg_source_balancer_weighted": "WeightedPool2Tokens",
"pkg_source_curve_aave": "AavePool",
"pkg_source_curve_base": "PoolBaseSimulator",
"pkg_source_curve_compound": "CompoundPool",
"pkg_source_curve_meta": "Pool",
"pkg_source_curve_plainoracle": "Pool",
"pkg_source_curve_tricrypto": "Pool",
"pkg_source_curve_two": "Pool",
"pkg_source_maverickv1": "Pool",
"pkg_source_velocimeter": "Pool",
}
)

func main() {
var paths []string

if dir := findGoModDirInParents(); dir != "" {
for _, path := range findAllPoolTestdataSourceFile(dir) {
path = strings.TrimPrefix(path, dir+"/")
paths = append(paths, path)
}
}

if len(paths) == 0 {
return
}

pkgNames := getPackageNamesFromSourceFiles(paths)
importPaths := getPackageImportPathsFromSourceFiles(paths)

outFile, err := os.Create("./register_pool_types.go")
if err != nil {
log.Fatalf("could not create dispatch_gen.go: %s", err)
}
defer outFile.Close()

outFileBuf := bufio.NewWriter(outFile)
defer outFileBuf.Flush()

emitImports(outFileBuf, pkgNames, importPaths)

fmt.Fprintf(outFileBuf, "func init() {\n")
for _, pkgName := range pkgNames {
poolSimName := regularPoolSimName
if name, ok := irregularPoolSimNameByPackageName[pkgName]; ok {
poolSimName = name
}
fmt.Fprintf(outFileBuf, "\tmsgpack.RegisterConcreteType(&%s.%s{})\n", pkgName, poolSimName)
}
fmt.Fprintf(outFileBuf, "}\n")

}

func emitImports(outFileBuf io.Writer, pkgNames, importPaths []string) {
fmt.Fprintf(outFileBuf, "package msgpack\n")
fmt.Fprintf(outFileBuf, "\n")

fmt.Fprintf(outFileBuf, "// Code generated by %s/pkg/msgpack/generate DO NOT EDIT.\n", moduleName)
fmt.Fprintf(outFileBuf, "\n")

fmt.Fprintf(outFileBuf, "import (\n")
fmt.Fprintf(outFileBuf, "\t\"github.com/KyberNetwork/msgpack/v5\"\n")
fmt.Fprintf(outFileBuf, "\n")
for i, dexName := range pkgNames {
fmt.Fprintf(outFileBuf, "\t%s \"%s\"\n", dexName, importPaths[i])
}
fmt.Fprintf(outFileBuf, ")\n")
}

func findGoModDirInParents() string {
var (
hasGoMod = false
cwd, _ = os.Getwd()
visited = make(map[string]struct{}) // to eliminate cycle
)
for {
if _, ok := visited[cwd]; ok {
break
}
visited[cwd] = struct{}{}

entries, err := os.ReadDir(cwd)
if err != nil {
break
}
for _, entry := range entries {
if entry.Name() == "go.mod" {
hasGoMod = true
break
}
}
if hasGoMod {
break
}

cwd = filepath.Join(cwd, "..")
cwd, err = filepath.Abs(cwd)
if err != nil {
break
}
}
if hasGoMod {
return cwd
}
return ""
}

func findAllPoolTestdataSourceFile(rootDir string) []string {
var paths []string
err := filepath.Walk(rootDir, func(path string, info fs.FileInfo, err error) error {
if err != nil {
return err
}
if info.IsDir() {
return nil
}
if strings.HasSuffix(path, "/"+poolSimFileName) {
paths = append(paths, path)
}
return nil
})
if err != nil {
panic(err)
}
return paths
}

func getPackageNamesFromSourceFiles(sourcePaths []string) []string {
importNames := make([]string, 0, len(sourcePaths))
for _, path := range sourcePaths {
dexName := strings.TrimSuffix(path, "/"+poolSimFileName)
dexName = strings.ReplaceAll(dexName, "-", "")
dexName = strings.ReplaceAll(dexName, "/", "_")
importNames = append(importNames, dexName)
}
return importNames
}

func getPackageImportPathsFromSourceFiles(sourcePaths []string) []string {
paths := make([]string, 0, len(sourcePaths))
for _, path := range sourcePaths {
importPath := filepath.Join(moduleName, strings.TrimSuffix(path, "/"+poolSimFileName))
paths = append(paths, importPath)
}
return paths
}
3 changes: 3 additions & 0 deletions pkg/msgpack/generate_register_pool_types.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
//go:generate go run ./generate

package msgpack
Loading

0 comments on commit b2951e2

Please sign in to comment.