mirror of https://github.com/certusone/dc4bc.git
storage works
This commit is contained in:
parent
b2e94d99b7
commit
f4d6c1e8a6
|
@ -2,15 +2,18 @@ package storage
|
|||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/cosmos/cosmos-sdk/crypto/keys"
|
||||
"github.com/cosmos/cosmos-sdk/types/rest"
|
||||
"github.com/cosmos/cosmos-sdk/x/auth"
|
||||
authRest "github.com/cosmos/cosmos-sdk/x/auth/client/rest"
|
||||
"github.com/cosmos/cosmos-sdk/x/auth/exported"
|
||||
"github.com/cosmos/cosmos-sdk/x/auth/types"
|
||||
"github.com/lidofinance/bulletin/app"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
type TendermintStorage struct {
|
||||
|
@ -24,7 +27,8 @@ type TendermintStorage struct {
|
|||
topic string
|
||||
}
|
||||
|
||||
func NewTendermintStorage(nodeEndpoint, name, chainID string, topic string, password, mnemonic string) (*TendermintStorage, error) {
|
||||
func NewTendermintStorage(nodeEndpoint, name, chainID string, topic string, password,
|
||||
mnemonic string) (Storage, error) {
|
||||
var ts TendermintStorage
|
||||
|
||||
ts.nodeEndpoint = nodeEndpoint
|
||||
|
@ -35,7 +39,8 @@ func NewTendermintStorage(nodeEndpoint, name, chainID string, topic string, pass
|
|||
|
||||
ts.keybase = keys.NewInMemory()
|
||||
hdPath := keys.CreateHDPath(0, 0).String()
|
||||
info, err := ts.keybase.CreateAccount(name, mnemonic, keys.DefaultBIP39Passphrase, password, hdPath, keys.Secp256k1)
|
||||
info, err := ts.keybase.CreateAccount(name, mnemonic, keys.DefaultBIP39Passphrase, password,
|
||||
hdPath, keys.Secp256k1)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -43,6 +48,11 @@ func NewTendermintStorage(nodeEndpoint, name, chainID string, topic string, pass
|
|||
return &ts, nil
|
||||
}
|
||||
|
||||
func (ts *TendermintStorage) Close() error {
|
||||
ts.keybase.CloseDB()
|
||||
return nil
|
||||
}
|
||||
|
||||
type getAccountResponse struct {
|
||||
Height string `json:"heignt"`
|
||||
Result exported.Account `json:"result"`
|
||||
|
@ -52,20 +62,24 @@ func (ts *TendermintStorage) getAccount(addr string) (exported.Account, error) {
|
|||
url := fmt.Sprintf("%s/auth/accounts/%s", ts.nodeEndpoint, addr)
|
||||
resp, err := http.Get(url)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, fmt.Errorf("failed to do HTTP GET request: %w", err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
var accountResponse getAccountResponse
|
||||
respBody, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, fmt.Errorf("failed to read response body: %w", err)
|
||||
}
|
||||
if err = app.MakeCodec().UnmarshalJSON(respBody, &accountResponse); err != nil {
|
||||
return nil, err
|
||||
return nil, fmt.Errorf("failed to unmarshal response body: %w", err)
|
||||
}
|
||||
return accountResponse.Result, nil
|
||||
}
|
||||
|
||||
type errorResp struct {
|
||||
Error string `json:"error"`
|
||||
}
|
||||
|
||||
func rawPostRequest(url string, contentType string, data []byte) ([]byte, error) {
|
||||
resp, err := http.Post(url,
|
||||
contentType, bytes.NewReader(data))
|
||||
|
@ -77,10 +91,29 @@ func rawPostRequest(url string, contentType string, data []byte) ([]byte, error)
|
|||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to read body %w", err)
|
||||
}
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
var errorResp errorResp
|
||||
if err = json.Unmarshal(responseBody, &errorResp); err != nil {
|
||||
return nil, fmt.Errorf("failed to unmarshal response: %w", err)
|
||||
}
|
||||
return nil, fmt.Errorf("%s", errorResp.Error)
|
||||
}
|
||||
return responseBody, nil
|
||||
}
|
||||
|
||||
type BulletinMessage struct {
|
||||
ID string `json:"id"`
|
||||
Creator string `json:"creator"`
|
||||
DKGRoundID string `json:"dkg_round_id"`
|
||||
Event string `json:"event"`
|
||||
Data []byte `json:"data"`
|
||||
Signature []byte `json:"signature"`
|
||||
Sender string `json:"sender"`
|
||||
Recipient string `json:"recipient"`
|
||||
Topic string `json:"topic"`
|
||||
Offset string `json:"offset"`
|
||||
}
|
||||
|
||||
type genTxRequest struct {
|
||||
BaseReq rest.BaseReq `json:"base_req"`
|
||||
Creator string `json:"creator"`
|
||||
|
@ -111,16 +144,17 @@ func (ts *TendermintStorage) genTx(msg Message) (*types.StdTx, error) {
|
|||
|
||||
data, err := app.MakeCodec().MarshalJSON(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, fmt.Errorf("failed to marshal request: %w", err)
|
||||
}
|
||||
resp, err := rawPostRequest(fmt.Sprintf("%s/bulletin/message", ts.nodeEndpoint), "application/json", data)
|
||||
resp, err := rawPostRequest(fmt.Sprintf("%s/bulletin/message", ts.nodeEndpoint),
|
||||
"application/json", data)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var tx auth.StdTx
|
||||
if err = app.MakeCodec().UnmarshalJSON(resp, &tx); err != nil {
|
||||
return nil, err
|
||||
return nil, fmt.Errorf("failed to unmarshal response: %w", err)
|
||||
}
|
||||
return &tx, nil
|
||||
}
|
||||
|
@ -128,12 +162,95 @@ func (ts *TendermintStorage) genTx(msg Message) (*types.StdTx, error) {
|
|||
func (ts *TendermintStorage) signTx(tx types.StdTx) (*types.StdTx, error) {
|
||||
account, err := ts.getAccount(ts.accountAddress)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, fmt.Errorf("failed to get account info: %w", err)
|
||||
}
|
||||
txBuilder := auth.NewTxBuilder(auth.DefaultTxEncoder(app.MakeCodec()), account.GetAccountNumber(), account.GetSequence(), tx.GetGas(), 0, false, ts.chainID, tx.GetMemo(), tx.Fee.Amount, tx.Fee.GasPrices()).WithKeybase(ts.keybase)
|
||||
txBuilder := auth.NewTxBuilder(auth.DefaultTxEncoder(app.MakeCodec()), account.GetAccountNumber(),
|
||||
account.GetSequence(), tx.GetGas(), 0, false, ts.chainID, tx.GetMemo(),
|
||||
tx.Fee.Amount, tx.Fee.GasPrices()).WithKeybase(ts.keybase)
|
||||
signedTx, err := txBuilder.SignStdTx(ts.name, ts.password, tx, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, fmt.Errorf("failed to sign tx: %w", err)
|
||||
}
|
||||
return &signedTx, nil
|
||||
}
|
||||
|
||||
func (ts *TendermintStorage) broadcastTx(tx types.StdTx) error {
|
||||
var req authRest.BroadcastReq
|
||||
req.Tx = tx
|
||||
req.Mode = "block"
|
||||
|
||||
data, err := app.MakeCodec().MarshalJSON(req)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err = rawPostRequest(fmt.Sprintf("%s/txs", ts.nodeEndpoint),
|
||||
"application/json", data); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ts *TendermintStorage) Send(msg Message) (Message, error) {
|
||||
tx, err := ts.genTx(msg)
|
||||
if err != nil {
|
||||
return msg, fmt.Errorf("failed to generate tx: %w", err)
|
||||
}
|
||||
signedTx, err := ts.signTx(*tx)
|
||||
if err != nil {
|
||||
return msg, fmt.Errorf("failed to sign tx: %w", err)
|
||||
}
|
||||
if err = ts.broadcastTx(*signedTx); err != nil {
|
||||
return msg, fmt.Errorf("failed to broadcast tx: %w", err)
|
||||
}
|
||||
return msg, nil
|
||||
}
|
||||
|
||||
type getMessagesResponse struct {
|
||||
Height string `json:"height"`
|
||||
Result []BulletinMessage `json:"result"`
|
||||
}
|
||||
|
||||
func (ts *TendermintStorage) GetMessages(offset uint64) ([]Message, error) {
|
||||
url := fmt.Sprintf("%s/bulletin/message/%s/%d", ts.nodeEndpoint, ts.topic, offset)
|
||||
resp, err := http.Get(url)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to do HTTP GET request: %w", err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
var messagesResponse getMessagesResponse
|
||||
respBody, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to read response body: %w", err)
|
||||
}
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
var errorResp errorResp
|
||||
if err = json.Unmarshal(respBody, &errorResp); err != nil {
|
||||
return nil, fmt.Errorf("failed to unmarshal response: %w", err)
|
||||
}
|
||||
return nil, fmt.Errorf("%w", err)
|
||||
}
|
||||
|
||||
if err = json.Unmarshal(respBody, &messagesResponse); err != nil {
|
||||
return nil, fmt.Errorf("failed to unmarshal response body: %w", err)
|
||||
}
|
||||
|
||||
msgs := make([]Message, len(messagesResponse.Result))
|
||||
for i, message := range messagesResponse.Result {
|
||||
parsedOffset, err := strconv.ParseUint(message.Offset, 10, 64)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to parse offset: %w", err)
|
||||
}
|
||||
msgs[i] = Message{
|
||||
ID: message.ID,
|
||||
DkgRoundID: message.DKGRoundID,
|
||||
Offset: parsedOffset,
|
||||
Event: message.Topic,
|
||||
Data: message.Data,
|
||||
Signature: message.Signature,
|
||||
SenderAddr: message.Sender,
|
||||
RecipientAddr: message.Recipient,
|
||||
}
|
||||
}
|
||||
return msgs, nil
|
||||
}
|
||||
|
|
|
@ -1,44 +1,47 @@
|
|||
package storage
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
const (
|
||||
TestEndpoint = "http://0.0.0.0:1317"
|
||||
TestUserName = "user1"
|
||||
TestChainID = "bulletin"
|
||||
TestTopic = "test_topic"
|
||||
TestPassword = "12345678"
|
||||
TestMnemonic = "weasel topic tube fun expire faculty panda nut gloom twice define evoke regular toss staff buffalo walk shell quote vote follow regular elephant invite"
|
||||
)
|
||||
|
||||
func TestNewTendermintStorage(t *testing.T) {
|
||||
ts, err := NewTendermintStorage("http://0.0.0.0:1317", "user1", "bulletin", "test_topic", "12345678", "trip spin bench ghost ride steak fame clutch desk lake fiction emotion pen peace spare output gun genuine soccer fury affair execute bar outdoor")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
info, err := ts.keybase.Get("user1")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
account, err := ts.getAccount(info.GetAddress().String())
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
fmt.Println(account.GetCoins())
|
||||
N := 10
|
||||
offset := 4
|
||||
|
||||
msg := Message{
|
||||
ID: "lsflksdjf",
|
||||
DkgRoundID: "1234",
|
||||
Offset: 0,
|
||||
Event: "test_event",
|
||||
Data: []byte{1, 2, 3, 4},
|
||||
Signature: []byte{1, 2, 3, 4},
|
||||
SenderAddr: "sender",
|
||||
RecipientAddr: "recipient",
|
||||
ts, err := NewTendermintStorage(TestEndpoint, TestUserName, TestChainID, TestTopic, TestPassword, TestMnemonic)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
msgs := make([]Message, 0, N)
|
||||
for i := 0; i < N; i++ {
|
||||
msg := Message{
|
||||
Data: randomBytes(10),
|
||||
Signature: randomBytes(10),
|
||||
}
|
||||
msg, err = ts.Send(msg)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
msgs = append(msgs, msg)
|
||||
}
|
||||
|
||||
tx, err := ts.genTx(msg)
|
||||
offsetMsgs, err := ts.GetMessages(uint64(offset))
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
signedTx, err := ts.signTx(*tx)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
expectedOffsetMsgs := msgs[offset:]
|
||||
for idx, msg := range expectedOffsetMsgs {
|
||||
reflect.DeepEqual(msg.Signature, offsetMsgs[idx].Signature)
|
||||
}
|
||||
fmt.Println(signedTx.GetSignatures())
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue