diff --git a/go.mod b/go.mod index 68b9903..19f95a7 100644 --- a/go.mod +++ b/go.mod @@ -5,6 +5,8 @@ go 1.21 toolchain go1.21.6 require ( + github.com/Salvionied/apollo v1.0.12 + github.com/SundaeSwap-finance/kugo v1.0.5 github.com/blinklabs-io/gouroboros v0.94.3 github.com/gen2brain/beeep v0.0.0-20230602101333-f384c29b62dd github.com/gin-gonic/gin v1.10.0 @@ -25,6 +27,10 @@ require ( cloud.google.com/go/compute/metadata v0.3.0 // indirect filippo.io/edwards25519 v1.1.0 // indirect github.com/KyleBanks/depth v1.2.1 // indirect + github.com/Salvionied/cbor/v2 v2.6.0 // indirect + github.com/SundaeSwap-finance/ogmigo/v6 v6.0.0-20231128043329-e8ced51013a1 // indirect + github.com/aws/aws-sdk-go v1.48.7 // indirect + github.com/buger/jsonparser v1.1.1 // indirect github.com/bytedance/sonic v1.11.6 // indirect github.com/bytedance/sonic/loader v0.1.1 // indirect github.com/cloudwego/base64x v0.1.4 // indirect @@ -43,7 +49,9 @@ require ( github.com/go-toast/toast v0.0.0-20190211030409-01e6764cf0a4 // indirect github.com/goccy/go-json v0.10.2 // indirect github.com/godbus/dbus/v5 v5.1.0 // indirect + github.com/gorilla/websocket v1.5.1 // indirect github.com/jinzhu/copier v0.4.0 // indirect + github.com/jmespath/go-jmespath v0.4.0 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/klauspost/cpuid/v2 v2.2.7 // indirect @@ -64,6 +72,7 @@ require ( golang.org/x/arch v0.8.0 // indirect golang.org/x/crypto v0.27.0 // indirect golang.org/x/net v0.25.0 // indirect + golang.org/x/sync v0.8.0 // indirect golang.org/x/sys v0.25.0 // indirect golang.org/x/text v0.18.0 // indirect golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect diff --git a/go.sum b/go.sum index 41f8c0a..8afa75a 100644 --- a/go.sum +++ b/go.sum @@ -4,10 +4,22 @@ filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= github.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc= github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6XgeJcm8brE= +github.com/Salvionied/apollo v1.0.12 h1:kC12bSqOQX7cZjKh9D4vqBX/VH9jZd9z+hPXdLZTalg= +github.com/Salvionied/apollo v1.0.12/go.mod h1:BLs3iWs5ovGcVqFvpuX3g0RmLB9QIYMwFgzcN9rhkGA= +github.com/Salvionied/cbor/v2 v2.6.0 h1:OEwlZLiodLdNeM9wFoSydLvj6/rHRaxu5G8VzwXSeuY= +github.com/Salvionied/cbor/v2 v2.6.0/go.mod h1:oFxaUo/mQ5sG1k459nzctGdYa80jy0ZqZ9pln9C/fGw= +github.com/SundaeSwap-finance/kugo v1.0.5 h1:GWUbHkAIIMh1SmGMCw5r0rpOvriRsEoLpp5ofufWRvs= +github.com/SundaeSwap-finance/kugo v1.0.5/go.mod h1:jkNGTmwLRdUPKVzkOOQjxqkpPTDw5gJ2hkJi3zUF9tA= +github.com/SundaeSwap-finance/ogmigo/v6 v6.0.0-20231128043329-e8ced51013a1 h1:Lfw4vCNhm5Ik5wdbPsCK8k4gphhCB2/jtLxY5s/EifA= +github.com/SundaeSwap-finance/ogmigo/v6 v6.0.0-20231128043329-e8ced51013a1/go.mod h1:CsDGcgbkKoz6S4h0RJ30go7oXG+KhGE2KLhBpRFnEqA= +github.com/aws/aws-sdk-go v1.48.7 h1:gDcOhmkohlNk20j0uWpko5cLBbwSkB+xpkshQO45F7Y= +github.com/aws/aws-sdk-go v1.48.7/go.mod h1:LF8svs817+Nz+DmiMQKTO3ubZ/6IaTpq3TjupRn3Eqk= github.com/blinklabs-io/gouroboros v0.94.3 h1:eR26ONYtxDA7Z8UPNyknwD95LBeSC6rzaYndM5Ai03g= github.com/blinklabs-io/gouroboros v0.94.3/go.mod h1:lfvV4sV5tNz/qkaLiR85pKpKqPlHfAa5wFhWGbgsXZ0= github.com/blinklabs-io/ouroboros-mock v0.3.3 h1:c6jN9qcLzNQSVh3zjPE61gF33UkkRRIiNqSGBkZ10cY= github.com/blinklabs-io/ouroboros-mock v0.3.3/go.mod h1:UXkR/8qA5w/WtkzffOIdXudgOndN99DEorgRwy4ynN8= +github.com/buger/jsonparser v1.1.1 h1:2PnMjfWD7wBILjqQbt530v576A/cAbQvEW9gGIpYMUs= +github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0= github.com/bytedance/sonic v1.11.6 h1:oUp34TzMlL+OY1OUWxHqsdkgC/Zfc85zGqw9siXjrc0= github.com/bytedance/sonic v1.11.6/go.mod h1:LysEHSvpvDySVdC2f87zGWf6CIKJcAvqab1ZaiQtds4= github.com/bytedance/sonic/loader v0.1.1 h1:c+e5Pt1k/cy5wMveRDyk2X4B9hF4g7an8N3zCYjJFNM= @@ -65,8 +77,14 @@ github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5x github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/gorilla/websocket v1.5.1 h1:gmztn0JnHVt9JZquRuzLw3g4wouNVzKL15iLr/zn/QY= +github.com/gorilla/websocket v1.5.1/go.mod h1:x3kM2JMyaluk02fnUJpQuwD2dCS5NDG2ZHL0uE0tcaY= github.com/jinzhu/copier v0.4.0 h1:w3ciUoD19shMCRargcpm0cm91ytaBhDvuRpz1ODO/U8= github.com/jinzhu/copier v0.4.0/go.mod h1:DfbEm0FYsaqBcKcFuvmOZb218JkPGtvSHsKg8S8hyyg= +github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= +github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= +github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8= +github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= @@ -100,6 +118,8 @@ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJ 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/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= +github.com/nsf/jsondiff v0.0.0-20210926074059-1e845ec5d249 h1:NHrXEjTNQY7P0Zfx1aMrNhpgxHmow66XQtm0aQLY0AE= +github.com/nsf/jsondiff v0.0.0-20210926074059-1e845ec5d249/go.mod h1:mpRZBD8SJ55OIICQ3iWH0Yz3cjzA61JdqMLoWXeB2+8= github.com/nu7hatch/gouuid v0.0.0-20131221200532-179d4d0c4d8d h1:VhgPp6v9qf9Agr/56bj7Y/xa04UccTW04VP0Qed4vnQ= github.com/nu7hatch/gouuid v0.0.0-20131221200532-179d4d0c4d8d/go.mod h1:YUTz3bUH2ZwIWBy3CJBeOBEugqcmXREj14T+iG/4k4U= github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM= @@ -132,6 +152,8 @@ github.com/swaggo/swag v1.16.3 h1:PnCYjPCah8FK4I26l2F/KQ4yz3sILcVUN3cTlBFA9Pg= github.com/swaggo/swag v1.16.3/go.mod h1:DImHIuOFXKpMFAQjcC7FG4m3Dg4+QuUgUzJmKjI/gRk= github.com/tadvi/systray v0.0.0-20190226123456-11a2b8fa57af h1:6yITBqGTE2lEeTPG04SN9W+iWHCRyHqlVYILiSXziwk= github.com/tadvi/systray v0.0.0-20190226123456-11a2b8fa57af/go.mod h1:4F09kP5F+am0jAwlQLddpoMDM+iewkxxt6nxUQ5nq5o= +github.com/tj/assert v0.0.3 h1:Df/BlaZ20mq6kuai7f5z2TvPFiwC3xaWJSDQNiIS3Rk= +github.com/tj/assert v0.0.3/go.mod h1:Ne6X72Q+TB1AteidzQncjw9PabbMp4PBMZ1k+vd1Pvk= github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE= @@ -199,6 +221,7 @@ gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8 gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/input/chainsync/chainsync.go b/input/chainsync/chainsync.go index acf7a54..ff468d1 100644 --- a/input/chainsync/chainsync.go +++ b/input/chainsync/chainsync.go @@ -15,13 +15,21 @@ package chainsync import ( + "context" "encoding/hex" "fmt" "time" + "github.com/Salvionied/apollo/serialization/MultiAsset" + "github.com/Salvionied/apollo/serialization/TransactionInput" + "github.com/Salvionied/apollo/serialization/TransactionOutput" + "github.com/Salvionied/apollo/serialization/UTxO" + "github.com/Salvionied/apollo/serialization/Value" + "github.com/SundaeSwap-finance/kugo" "github.com/blinklabs-io/adder/event" "github.com/blinklabs-io/adder/plugin" + serAddress "github.com/Salvionied/apollo/serialization/Address" ouroboros "github.com/blinklabs-io/gouroboros" "github.com/blinklabs-io/gouroboros/ledger" "github.com/blinklabs-io/gouroboros/protocol/blockfetch" @@ -59,6 +67,7 @@ type ChainSync struct { cursorCache []ocommon.Point dialAddress string dialFamily string + kupoUrl string } type ChainSyncStatus struct { @@ -318,6 +327,32 @@ func (c *ChainSync) handleRollForward( blockEvt := event.New("chainsync.block", time.Now(), NewBlockHeaderContext(v), NewBlockEvent(block, c.includeCbor)) c.eventChan <- blockEvt for t, transaction := range block.Transactions() { + // Use Kupo client to resolve inputs if it is available + if c.kupoUrl != "" { + k, err := getKupoClient(c) + if err != nil { + return fmt.Errorf("failed to get Kupo client: %w", err) + } + matches, err := k.Matches( + context.Background(), + kugo.Pattern(c.address), + ) + if err != nil { + return fmt.Errorf("failed to resolve inputs with Kupo: %w", err) + } + + resolvedInputs := []UTxO.UTxO{} + for _, match := range matches { + // TODO - finish kupoMatchToApolloUtxo + tmpUtxo, err := kupoMatchToApolloUtxo(match) + if err != nil { + return fmt.Errorf("failed to convert Kupo match to Apollo UTxO: %w", err) + } + // TODO - add resolvedInputs to the transaction + resolvedInputs = append(resolvedInputs, tmpUtxo) + } + + } txEvt := event.New("chainsync.transaction", time.Now(), NewTransactionContext(block, transaction, uint32(t), c.networkMagic), NewTransactionEvent(block, transaction, c.includeCbor)) c.eventChan <- txEvt } @@ -403,3 +438,39 @@ func (c *ChainSync) updateStatus( c.statusUpdateFunc(*(c.status)) } } + +func getKupoClient(c *ChainSync) (*kugo.Client, error) { + k := kugo.New(kugo.WithEndpoint(c.kupoUrl)) + return k, nil +} + +func kupoMatchToApolloUtxo(match kugo.Match) (UTxO.UTxO, error) { + serAddr, _ := serAddress.DecodeAddress(match.Address) + txIdBytes, _ := hex.DecodeString(match.TransactionID) + assets := make(MultiAsset.MultiAsset[int64]) + // TODO - find how to get Assets or replacment + // for assetId, assetAmount := range match.Value.Assets { + // tmpPolicyId := Policy.PolicyId{Value: assetId.PolicyID()} + // tmpAssetName := AssetName.NewAssetNameFromString(assetId.AssetName()) + // if _, ok := assets[tmpPolicyId]; !ok { + // assets[tmpPolicyId] = Asset.Asset[int64]{} + // } + // assets[tmpPolicyId][tmpAssetName] = assetAmount.Int64() + // } + val := Value.SimpleValue( + // TODO - Dummy value missing coins + 123, + assets, + ) + ret := UTxO.UTxO{ + Input: TransactionInput.TransactionInput{ + TransactionId: txIdBytes, + Index: match.OutputIndex, + }, + Output: TransactionOutput.SimpleTransactionOutput( + serAddr, + val, + ), + } + return ret, nil +} diff --git a/input/chainsync/options.go b/input/chainsync/options.go index d382d3b..13e4ae7 100644 --- a/input/chainsync/options.go +++ b/input/chainsync/options.go @@ -107,3 +107,9 @@ func WithBulkMode(bulkMode bool) ChainSyncOptionFunc { c.bulkMode = bulkMode } } + +func WithKupoUrl(kupoUrl string) ChainSyncOptionFunc { + return func(c *ChainSync) { + c.kupoUrl = kupoUrl + } +} diff --git a/input/chainsync/plugin.go b/input/chainsync/plugin.go index 0dec06b..91d57b0 100644 --- a/input/chainsync/plugin.go +++ b/input/chainsync/plugin.go @@ -36,6 +36,7 @@ var cmdlineOptions struct { intersectPoint string includeCbor bool autoReconnect bool + kupoUrl string } func init() { @@ -118,6 +119,13 @@ func init() { DefaultValue: true, Dest: &(cmdlineOptions.autoReconnect), }, + { + Name: "kupo-url", + Type: plugin.PluginOptionTypeString, + Description: "kupo-url address", + DefaultValue: "", + Dest: &(cmdlineOptions.kupoUrl), + }, }, }, ) @@ -136,6 +144,7 @@ func NewFromCmdlineOptions() plugin.Plugin { WithBulkMode(cmdlineOptions.bulkMode), WithIncludeCbor(cmdlineOptions.includeCbor), WithAutoReconnect(cmdlineOptions.autoReconnect), + WithKupoUrl(cmdlineOptions.kupoUrl), } if cmdlineOptions.intersectPoint != "" { intersectPoints := []ocommon.Point{}