chore: replace elementsd-connector with shamir-coordinator-client (#422)

* chore: replace elementsd-connector with shamir-coordinator-client
---------

Signed-off-by: Lorenz Herzberger <lorenzherzberger@gmail.com>
This commit is contained in:
Lorenz Herzberger 2024-07-03 09:54:42 +02:00 committed by GitHub
parent d2def2b453
commit 3ffd9f96ef
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 65 additions and 151 deletions

View File

@ -50,11 +50,21 @@ func ReIssueAsset(ctx context.Context, asset string, amount string) (txID string
return res.TxID, nil
}
func IssueNFTAsset(ctx context.Context, name string, machineAddress string, domain string) (assetID string, contract string, hexTx string, err error) {
client := lazyLoadShamirCoordinatorClient()
res, err := client.IssueMachineNFT(ctx, name, machineAddress, domain)
if err != nil {
return
}
return res.Asset, res.Contract, res.HexTX, nil
}
type IShamirCoordinatorClient interface {
GetMnemonics(ctx context.Context) (res MnemonicsResponse, err error)
PostMnemonics(ctx context.Context, secret string) (err error)
SendTokens(ctx context.Context, recipient string, amount string, asset string) (res SendTokensResponse, err error)
ReIssueAsset(ctx context.Context, asset string, amount string) (res ReIssueResponse, err error)
IssueMachineNFT(ctx context.Context, name string, machineAddress string, domain string) (res IssueMachineNFTResponse, err error)
}
type SendTokensRequest struct {
@ -81,6 +91,18 @@ type MnemonicsResponse struct {
Seed string `binding:"required" json:"seed"`
}
type IssueMachineNFTRequest struct {
Name string `binding:"required" json:"name"`
MachineAddress string `binding:"required" json:"machine-address"`
Domain string `binding:"required" json:"domain"`
}
type IssueMachineNFTResponse struct {
Asset string `binding:"required" json:"asset"`
Contract string `binding:"required" json:"contract"`
HexTX string `binding:"required" json:"hex-tx"`
}
type ShamirCoordinatorClient struct {
baseURL string
client *http.Client
@ -125,6 +147,16 @@ func (scc *ShamirCoordinatorClient) ReIssueAsset(ctx context.Context, asset stri
return
}
func (scc *ShamirCoordinatorClient) IssueMachineNFT(ctx context.Context, name string, machineAddress string, domain string) (res IssueMachineNFTResponse, err error) {
requestBody := IssueMachineNFTRequest{
Name: name,
MachineAddress: machineAddress,
Domain: domain,
}
err = scc.doRequest(ctx, http.MethodPost, scc.baseURL+"/issue-machine-nft", &requestBody, &res)
return
}
func (scc *ShamirCoordinatorClient) doRequest(ctx context.Context, method, url string, body interface{}, response interface{}) (err error) {
var bodyReader io.Reader
if body != nil {

View File

@ -50,6 +50,21 @@ func (mr *MockIShamirCoordinatorClientMockRecorder) GetMnemonics(ctx interface{}
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetMnemonics", reflect.TypeOf((*MockIShamirCoordinatorClient)(nil).GetMnemonics), ctx)
}
// IssueMachineNFT mocks base method.
func (m *MockIShamirCoordinatorClient) IssueMachineNFT(ctx context.Context, name, machineAddress, domain string) (clients.IssueMachineNFTResponse, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "IssueMachineNFT", ctx, name, machineAddress, domain)
ret0, _ := ret[0].(clients.IssueMachineNFTResponse)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// IssueMachineNFT indicates an expected call of IssueMachineNFT.
func (mr *MockIShamirCoordinatorClientMockRecorder) IssueMachineNFT(ctx, name, machineAddress, domain interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IssueMachineNFT", reflect.TypeOf((*MockIShamirCoordinatorClient)(nil).IssueMachineNFT), ctx, name, machineAddress, domain)
}
// PostMnemonics mocks base method.
func (m *MockIShamirCoordinatorClient) PostMnemonics(ctx context.Context, secret string) error {
m.ctrl.T.Helper()

View File

@ -62,6 +62,11 @@ func Load(t *testing.T, configs ...Config) *Network {
shamirMock.EXPECT().ReIssueAsset(gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes().Return(clients.ReIssueResponse{
TxID: "7add40beb27df701e02ee85089c5bc0021bc813823fedb5f1dcb5debda7f3da9",
}, nil)
shamirMock.EXPECT().IssueMachineNFT(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes().Return(clients.IssueMachineNFTResponse{
HexTX: "0000000000000000000000000000000000000000000000000000000000000000",
Contract: `{"entity":{"domain":"testnet-assets.rddl.io"}, "issuer_pubkey":"02", "machine_addr":"addr","name":"machine","precicion":8,"version":1}`,
Asset: "0000000000000000000000000000000000000000000000000000000000000000",
}, nil)
clients.ShamirCoordinatorServiceClient = shamirMock
// enable application logger in tests

View File

@ -1,112 +0,0 @@
package util
import (
"crypto/sha256"
"encoding/json"
"fmt"
"sync"
"github.com/planetmint/planetmint-go/config"
"github.com/planetmint/planetmint-go/x/machine/types"
elements "github.com/rddl-network/elements-rpc"
)
var (
// this mutex has to protect all signing and crafting of transactions and their inputs
// so that UTXOs are not spend twice by accident
elementsSyncAccess sync.Mutex
)
func IssueNFTAsset(name string, machineAddress string, domain string) (assetID string, contract string, hexTx string, err error) {
conf := config.GetConfig()
url := conf.GetRPCURL()
address, err := elements.GetNewAddress(url, []string{``})
if err != nil {
return
}
addressInfo, err := elements.GetAddressInfo(url, []string{`"` + address + `"`})
if err != nil {
return
}
elementsSyncAccess.Lock()
defer elementsSyncAccess.Unlock()
hex, err := elements.CreateRawTransaction(url, []string{`[]`, `[{"data":"00"}]`})
if err != nil {
return
}
fundRawTransactionResult, err := elements.FundRawTransaction(url, []string{`"` + hex + `"`, `{"feeRate":0.00001000}`})
if err != nil {
return
}
c := types.Contract{
Entity: types.Entity{
Domain: domain,
},
IssuerPubkey: addressInfo.Pubkey,
MachineAddr: machineAddress,
Name: name,
Precision: 0,
Version: 0,
}
contractBytes, err := json.Marshal(c)
if err != nil {
return
}
// e.g. {"entity":{"domain":"testnet-assets.rddl.io"}, "issuer_pubkey":"02...}
contract = string(contractBytes)
h := sha256.New()
_, err = h.Write(contractBytes)
if err != nil {
return
}
// e.g. 7ca8bb403ee5dccddef7b89b163048cf39439553f0402351217a4a03d2224df8
hash := h.Sum(nil)
// Reverse hash, e.g. f84d22d2034a7a21512340f053954339cf4830169bb8f7decddce53e40bba87c
for i, j := 0, len(hash)-1; i < j; i, j = i+1, j-1 {
hash[i], hash[j] = hash[j], hash[i]
}
rawIssueAssetResults, err := elements.RawIssueAsset(url, []string{`"` + fundRawTransactionResult.Hex + `"`,
`[{"asset_amount":0.00000001, "asset_address":"` + address + `", "blind":false, "contract_hash":"` + fmt.Sprintf("%+x", hash) + `"}]`,
})
if err != nil {
return
}
rawIssueAssetResult := rawIssueAssetResults[len(rawIssueAssetResults)-1]
hex, err = elements.BlindRawTransaction(url, []string{`"` + rawIssueAssetResult.Hex + `"`, `true`, `[]`, `false`})
if err != nil {
return
}
assetID = rawIssueAssetResult.Asset
signRawTransactionWithWalletResult, err := elements.SignRawTransactionWithWallet(url, []string{`"` + hex + `"`})
if err != nil {
return
}
testMempoolAcceptResults, err := elements.TestMempoolAccept(url, []string{`["` + signRawTransactionWithWalletResult.Hex + `"]`})
if err != nil {
return
}
testMempoolAcceptResult := testMempoolAcceptResults[len(testMempoolAcceptResults)-1]
if !testMempoolAcceptResult.Allowed {
err = fmt.Errorf("not accepted by mempool: %+v %+v", testMempoolAcceptResult, signRawTransactionWithWalletResult)
return
}
hex, err = elements.SendRawTransaction(url, []string{`"` + signRawTransactionWithWalletResult.Hex + `"`})
if err != nil {
return
}
return assetID, contract, hex, err
}

View File

@ -1,38 +0,0 @@
package util_test
import (
"math/rand"
"strconv"
"sync"
"testing"
"github.com/planetmint/planetmint-go/testutil/moduleobject"
"github.com/planetmint/planetmint-go/testutil/sample"
"github.com/planetmint/planetmint-go/util"
"github.com/planetmint/planetmint-go/x/machine/types"
elements "github.com/rddl-network/elements-rpc"
elementsmocks "github.com/rddl-network/elements-rpc/utils/mocks"
"github.com/stretchr/testify/assert"
)
func TestIssueNFTAsset(t *testing.T) {
elements.Client = &elementsmocks.MockClient{}
params := types.DefaultParams()
var wg sync.WaitGroup
for i := 0; i < 1; i++ {
wg.Add(1)
go func() {
randomInt := rand.Int()
sk, pk := sample.KeyPair(randomInt)
machine := moduleobject.MachineRandom(pk, pk, sk, "address "+strconv.Itoa(randomInt), randomInt)
_, _, _, err := util.IssueNFTAsset(machine.Name, machine.Address, params.AssetRegistryDomain)
assert.NoError(t, err)
wg.Done()
}()
}
wg.Wait()
}

View File

@ -12,6 +12,7 @@ import (
errorsmod "cosmossdk.io/errors"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/planetmint/planetmint-go/clients"
"github.com/planetmint/planetmint-go/x/machine/types"
)
@ -32,7 +33,7 @@ func IssueMachineNFT(goCtx context.Context, machine *types.Machine, scheme strin
// asset registration is in order to have the contact published
var notarizedAsset types.LiquidAsset
notarizedAsset.Registered = true
assetID, contract, hex, err := IssueNFTAsset(machine.Name, machine.Address, domain)
assetID, contract, hex, err := clients.IssueNFTAsset(goCtx, machine.Name, machine.Address, domain)
if err != nil {
GetAppLogger().Error(ctx, err.Error())
return err

View File

@ -9,7 +9,10 @@ import (
"testing"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/golang/mock/gomock"
"github.com/planetmint/planetmint-go/clients"
"github.com/planetmint/planetmint-go/testutil/keeper"
clientmocks "github.com/planetmint/planetmint-go/testutil/mocks"
"github.com/planetmint/planetmint-go/testutil/moduleobject"
"github.com/planetmint/planetmint-go/testutil/sample"
"github.com/planetmint/planetmint-go/util"
@ -47,7 +50,15 @@ func TestRegisterNFT(t *testing.T) {
}
func TestMachineNFTIssuance(t *testing.T) {
ctrl := gomock.NewController(t)
elements.Client = &elementsmocks.MockClient{}
shamirMock := clientmocks.NewMockIShamirCoordinatorClient(ctrl)
shamirMock.EXPECT().IssueMachineNFT(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes().Return(clients.IssueMachineNFTResponse{
HexTX: "0000000000000000000000000000000000000000000000000000000000000000",
Contract: `{"entity":{"domain":"testnet-assets.rddl.io"}, "issuer_pubkey":"02", "machine_addr":"addr","name":"machine","precicion":8,"version":1}`,
Asset: "0000000000000000000000000000000000000000000000000000000000000000",
}, nil)
clients.ShamirCoordinatorServiceClient = shamirMock
util.RegisterAssetServiceHTTPClient = &mocks.MockClient{}
_, ctx := keeper.MachineKeeper(t)
params := types.DefaultParams()