add: fixed ed25519 cryptography, added ethereum subscription, solana client integration into node, miner and consensus changes
This commit is contained in:
parent
54ac2c6c8d
commit
2526f65825
2
.gitignore
vendored
2
.gitignore
vendored
@ -20,4 +20,6 @@
|
||||
eth-contracts/node_modules
|
||||
/dione
|
||||
/.dione-config.toml
|
||||
/.dione-config-2.toml
|
||||
/.dione-config-3.toml
|
||||
eth-contracts/build
|
@ -9,6 +9,7 @@ import (
|
||||
type Config struct {
|
||||
ListenPort int `mapstructure:"listen_port"`
|
||||
ListenAddr string `mapstructure:"listen_addr"`
|
||||
IsBootstrap bool `mapstructure:"is_bootstrap"`
|
||||
BootstrapNodes []string `mapstructure:"bootstrap_node_multiaddr"`
|
||||
Rendezvous string `mapstructure:"rendezvous"`
|
||||
Ethereum EthereumConfig `mapstructure:"ethereum"`
|
||||
@ -23,6 +24,7 @@ type EthereumConfig struct {
|
||||
PrivateKey string `mapstructure:"private_key"`
|
||||
OracleEmitterContractAddress string `mapstructure:"oracle_emitter_contract_address"`
|
||||
AggregatorContractAddress string `mapstructure:"aggregator_contract_address"`
|
||||
DioneStakingContractAddress string `mapstructure:"dione_staking_address"`
|
||||
}
|
||||
|
||||
type FilecoinConfig struct {
|
||||
|
@ -11,9 +11,9 @@ import (
|
||||
type ConsensusState int
|
||||
|
||||
const (
|
||||
consensusPrePrepared ConsensusState = 0x0
|
||||
consensusPrepared ConsensusState = 0x1
|
||||
consensusCommitted ConsensusState = 0x2
|
||||
ConsensusPrePrepared ConsensusState = 0x0
|
||||
ConsensusPrepared ConsensusState = 0x1
|
||||
ConsensusCommitted ConsensusState = 0x2
|
||||
|
||||
testValidData = "test"
|
||||
)
|
||||
@ -60,7 +60,7 @@ func (pcm *PBFTConsensusManager) NewTestConsensus(data string, consensusID strin
|
||||
msg.Payload["data"] = data
|
||||
pcm.psb.BroadcastToServiceTopic(&msg)
|
||||
|
||||
cData.State = consensusPrePrepared
|
||||
cData.State = ConsensusPrePrepared
|
||||
logrus.Debug("started new consensus: " + consensusID)
|
||||
}
|
||||
|
||||
@ -99,7 +99,7 @@ func (pcm *PBFTConsensusManager) handlePreparedMessage(message *models.Message)
|
||||
logrus.Warn("Unable to send COMMIT message: " + err.Error())
|
||||
return
|
||||
}
|
||||
data.State = consensusPrepared
|
||||
data.State = ConsensusPrepared
|
||||
}
|
||||
}
|
||||
|
||||
@ -115,7 +115,7 @@ func (pcm *PBFTConsensusManager) handleCommitMessage(message *models.Message) {
|
||||
|
||||
data.mutex.Lock()
|
||||
defer data.mutex.Unlock()
|
||||
if data.State == consensusCommitted {
|
||||
if data.State == ConsensusCommitted {
|
||||
logrus.Debug("consensus already finished, dropping COMMIT message")
|
||||
return
|
||||
}
|
||||
@ -125,7 +125,7 @@ func (pcm *PBFTConsensusManager) handleCommitMessage(message *models.Message) {
|
||||
data.commitCount++
|
||||
|
||||
if data.commitCount > 2*pcm.maxFaultNodes+1 {
|
||||
data.State = consensusCommitted
|
||||
data.State = ConsensusCommitted
|
||||
data.result = message.Payload["data"].(string)
|
||||
logrus.Debug("consensus successfully finished with result: " + data.result)
|
||||
data.onConsensusFinishCallback(data.result)
|
||||
|
@ -2,9 +2,13 @@ package consensus
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"sync"
|
||||
|
||||
"github.com/Secured-Finance/dione/beacon"
|
||||
"github.com/Secured-Finance/dione/contracts/oracleEmitter"
|
||||
"github.com/Secured-Finance/dione/solana"
|
||||
solTypes "github.com/Secured-Finance/dione/solana/types"
|
||||
|
||||
"github.com/libp2p/go-libp2p-core/peer"
|
||||
|
||||
@ -23,6 +27,7 @@ type Miner struct {
|
||||
mutex sync.Mutex
|
||||
beacon beacon.BeaconNetworks
|
||||
ethClient *ethclient.EthereumClient
|
||||
solanaClient *solana.SolanaClient
|
||||
minerStake types.BigInt
|
||||
networkStake types.BigInt
|
||||
}
|
||||
@ -33,13 +38,15 @@ func NewMiner(
|
||||
api WalletAPI,
|
||||
beacon beacon.BeaconNetworks,
|
||||
ethClient *ethclient.EthereumClient,
|
||||
solanaClient *solana.SolanaClient,
|
||||
) *Miner {
|
||||
return &Miner{
|
||||
address: address,
|
||||
ethAddress: ethAddress,
|
||||
api: api,
|
||||
beacon: beacon,
|
||||
ethClient: ethClient,
|
||||
address: address,
|
||||
ethAddress: ethAddress,
|
||||
api: api,
|
||||
beacon: beacon,
|
||||
ethClient: ethClient,
|
||||
solanaClient: solanaClient,
|
||||
}
|
||||
}
|
||||
|
||||
@ -68,7 +75,7 @@ func (m *Miner) UpdateCurrentStakeInfo() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Miner) MineTask(ctx context.Context, payload []byte) (*types.DioneTask, error) {
|
||||
func (m *Miner) MineTask(ctx context.Context, event *oracleEmitter.OracleEmitterNewOracleRequest, sign SignFunc) (*types.DioneTask, error) {
|
||||
bvals, err := beacon.BeaconEntriesForTask(ctx, m.beacon)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("failed to get beacon entries: %w", err)
|
||||
@ -94,14 +101,31 @@ func (m *Miner) MineTask(ctx context.Context, payload []byte) (*types.DioneTask,
|
||||
if winner == nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
res, err := m.solanaClient.GetTransaction(event.RequestParams)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("Couldn't get solana request: %w", err)
|
||||
}
|
||||
response := res.Body()
|
||||
var txRes solTypes.TxResponse
|
||||
if err = json.Unmarshal(response, &txRes); err != nil {
|
||||
return nil, xerrors.Errorf("Couldn't unmarshal solana response: %w", err)
|
||||
}
|
||||
blockHash := txRes.Result.Transaction.Message.RecentBlockhash
|
||||
signature, err := sign(ctx, m.address, response)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("Couldn't sign solana response: %w", err)
|
||||
}
|
||||
|
||||
return &types.DioneTask{
|
||||
Miner: m.address,
|
||||
Ticket: ticket,
|
||||
ElectionProof: winner,
|
||||
BeaconEntries: bvals,
|
||||
Payload: payload,
|
||||
// TODO: signature
|
||||
DrandRound: types.DrandRound(rbase.Round),
|
||||
Payload: response,
|
||||
BlockHash: blockHash,
|
||||
Signature: signature,
|
||||
DrandRound: types.DrandRound(rbase.Round),
|
||||
}, nil
|
||||
}
|
||||
|
||||
|
@ -5,8 +5,9 @@ import (
|
||||
"math/big"
|
||||
|
||||
"github.com/Secured-Finance/dione/contracts/aggregator"
|
||||
"github.com/Secured-Finance/dione/contracts/dioneStaking"
|
||||
stakingContract "github.com/Secured-Finance/dione/contracts/dioneStaking"
|
||||
oracleEmitter "github.com/Secured-Finance/dione/contracts/oracleemitter"
|
||||
oracleEmitter "github.com/Secured-Finance/dione/contracts/oracleEmitter"
|
||||
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
@ -44,7 +45,7 @@ func NewEthereumClient() *EthereumClient {
|
||||
return ethereumClient
|
||||
}
|
||||
|
||||
func (c *EthereumClient) Initialize(ctx context.Context, url, privateKey, oracleEmitterContractAddress, aggregatorContractAddress string) error {
|
||||
func (c *EthereumClient) Initialize(ctx context.Context, url, privateKey, oracleEmitterContractAddress, aggregatorContractAddress, dioneStakingAddress string) error {
|
||||
client, err := ethclient.Dial(url)
|
||||
if err != nil {
|
||||
return err
|
||||
@ -66,6 +67,10 @@ func (c *EthereumClient) Initialize(ctx context.Context, url, privateKey, oracle
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
stakingContract, err := dioneStaking.NewDioneStaking(common.HexToAddress(dioneStakingAddress), client)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
c.oracleEmitter = &oracleEmitter.OracleEmitterSession{
|
||||
Contract: emitter,
|
||||
CallOpts: bind.CallOpts{
|
||||
@ -96,6 +101,21 @@ func (c *EthereumClient) Initialize(ctx context.Context, url, privateKey, oracle
|
||||
Context: context.Background(),
|
||||
},
|
||||
}
|
||||
c.dioneStaking = &dioneStaking.DioneStakingSession{
|
||||
Contract: stakingContract,
|
||||
CallOpts: bind.CallOpts{
|
||||
Pending: true,
|
||||
From: authTransactor.From,
|
||||
Context: context.Background(),
|
||||
},
|
||||
TransactOpts: bind.TransactOpts{
|
||||
From: authTransactor.From,
|
||||
Signer: authTransactor.Signer,
|
||||
GasLimit: 0, // 0 automatically estimates gas limit
|
||||
GasPrice: nil, // nil automatically suggests gas price
|
||||
Context: context.Background(),
|
||||
},
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -103,12 +123,12 @@ func (c *EthereumClient) GetEthAddress() *common.Address {
|
||||
return c.ethAddress
|
||||
}
|
||||
|
||||
func (c *EthereumClient) SubscribeOnOracleEvents() (chan *oracleEmitter.OracleEmitterNewOracleRequest, event.Subscription, error) {
|
||||
func (c *EthereumClient) SubscribeOnOracleEvents(ctx context.Context) (chan *oracleEmitter.OracleEmitterNewOracleRequest, event.Subscription, error) {
|
||||
resChan := make(chan *oracleEmitter.OracleEmitterNewOracleRequest)
|
||||
requestsFilter := c.oracleEmitter.Contract.OracleEmitterFilterer
|
||||
subscription, err := requestsFilter.WatchNewOracleRequest(&bind.WatchOpts{
|
||||
Start: nil, //last block
|
||||
Context: nil,
|
||||
Context: ctx,
|
||||
}, resChan)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
|
49
node/ethereum.go
Normal file
49
node/ethereum.go
Normal file
@ -0,0 +1,49 @@
|
||||
package node
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/Secured-Finance/dione/consensus"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
func (n *Node) subscribeOnEthContracts(ctx context.Context) {
|
||||
eventChan, subscription, err := n.Ethereum.SubscribeOnOracleEvents(ctx)
|
||||
if err != nil {
|
||||
logrus.Fatal("Can't subscribe on ethereum contracts, exiting... ", err)
|
||||
}
|
||||
|
||||
go func() {
|
||||
EventLoop:
|
||||
for {
|
||||
select {
|
||||
case event := <-eventChan:
|
||||
{
|
||||
task, err := n.Miner.MineTask(ctx, event, n.Wallet.WalletSign)
|
||||
if err != nil {
|
||||
logrus.Fatal("Error with mining algorithm, exiting... ", err)
|
||||
}
|
||||
logrus.Info("BlockHash for Solana transaction: ", task.BlockHash)
|
||||
logrus.Info("Started new consensus round with ID: ", task.BlockHash)
|
||||
n.ConsensusManager.NewTestConsensus(string(task.BlockHash), task.BlockHash, func(finalData string) {
|
||||
if finalData != string(task.BlockHash) {
|
||||
logrus.Warn("Expected final data to be %s, not %s", finalData)
|
||||
}
|
||||
})
|
||||
|
||||
if n.ConsensusManager.Consensuses[task.BlockHash].State == consensus.ConsensusCommitted {
|
||||
logrus.Info("Consensus ID: ", task.BlockHash, " was successfull")
|
||||
logrus.Info("Submitting on-chain result: ", task.BlockHash, "for consensus ID: ", task.BlockHash)
|
||||
if err := n.Ethereum.SubmitRequestAnswer(event.RequestID, task.BlockHash, event.CallbackAddress, event.CallbackMethodID); err != nil {
|
||||
logrus.Warn("Can't submit request to ethereum chain: ", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
case <-ctx.Done():
|
||||
break EventLoop
|
||||
case <-subscription.Err():
|
||||
logrus.Fatal("Error with ethereum subscription, exiting... ", err)
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
@ -70,6 +70,7 @@ func (n *Node) setupNode(ctx context.Context, prvKey crypto.PrivKey, pexDiscover
|
||||
if err != nil {
|
||||
logrus.Fatal(err)
|
||||
}
|
||||
n.setupSolanaClient()
|
||||
n.setupPubsub()
|
||||
n.setupConsensusManager(n.Config.ConsensusMaxFaultNodes)
|
||||
err = n.setupBeacon()
|
||||
@ -84,10 +85,11 @@ func (n *Node) setupNode(ctx context.Context, prvKey crypto.PrivKey, pexDiscover
|
||||
if err != nil {
|
||||
logrus.Fatal(err)
|
||||
}
|
||||
n.subscribeOnEthContracts(ctx)
|
||||
}
|
||||
|
||||
func (n *Node) setupMiner() error {
|
||||
n.Miner = consensus.NewMiner(n.Host.ID(), *n.Ethereum.GetEthAddress(), n.Wallet, n.Beacon, n.Ethereum)
|
||||
n.Miner = consensus.NewMiner(n.Host.ID(), *n.Ethereum.GetEthAddress(), n.Wallet, n.Beacon, n.Ethereum, n.Solana)
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -129,6 +131,7 @@ func (n *Node) setupEthereumClient() error {
|
||||
n.Config.Ethereum.PrivateKey,
|
||||
n.Config.Ethereum.OracleEmitterContractAddress,
|
||||
n.Config.Ethereum.AggregatorContractAddress,
|
||||
n.Config.Ethereum.DioneStakingContractAddress,
|
||||
)
|
||||
}
|
||||
|
||||
@ -177,7 +180,9 @@ func (n *Node) setupLibp2pHost(ctx context.Context, privateKey crypto.PrivKey, p
|
||||
}
|
||||
bootstrapMaddrs = append(bootstrapMaddrs, maddr)
|
||||
}
|
||||
|
||||
if n.Config.IsBootstrap {
|
||||
bootstrapMaddrs = nil
|
||||
}
|
||||
discovery, err := pex.NewPEXDiscovery(host, bootstrapMaddrs, pexDiscoveryUpdateTime)
|
||||
if err != nil {
|
||||
logrus.Fatal("Can't set up PEX discovery protocol, exiting... ", err)
|
||||
|
@ -22,13 +22,13 @@ func (ed25519Signer) GenPrivate() ([]byte, error) {
|
||||
}
|
||||
|
||||
func (ed25519Signer) ToPublic(priv []byte) ([]byte, error) {
|
||||
privKey := ed25519.NewKeyFromSeed(priv)
|
||||
var privKey ed25519.PrivateKey = priv
|
||||
pubKey := privKey.Public().(ed25519.PublicKey)
|
||||
return pubKey, nil
|
||||
}
|
||||
|
||||
func (ed25519Signer) Sign(p []byte, msg []byte) ([]byte, error) {
|
||||
privKey := ed25519.NewKeyFromSeed(p)
|
||||
var privKey ed25519.PrivateKey = p
|
||||
return ed25519.Sign(privKey, msg), nil
|
||||
}
|
||||
|
||||
|
@ -44,7 +44,7 @@ func (c *SolanaClient) GetTransaction(txHash string) (*fasthttp.Response, error)
|
||||
req.Header.SetMethod("POST")
|
||||
req.Header.SetContentType("application/json")
|
||||
requestBody := rpc.NewRequestBody("getConfirmedTransaction")
|
||||
requestBody.Params = append(requestBody.Params, txHash, "base58")
|
||||
requestBody.Params = append(requestBody.Params, txHash, "json")
|
||||
body, err := json.Marshal(requestBody)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Failed to marshal request body %v", err)
|
||||
|
45
solana/types/transaction.go
Normal file
45
solana/types/transaction.go
Normal file
@ -0,0 +1,45 @@
|
||||
package types
|
||||
|
||||
type TxResponse struct {
|
||||
Jsonrpc string `json:"jsonrpc"`
|
||||
Result TxResult `json:"result"`
|
||||
ID int `json:"id"`
|
||||
}
|
||||
|
||||
type TxStatus struct {
|
||||
Ok interface{} `json:"Ok"`
|
||||
}
|
||||
type TxMeta struct {
|
||||
Err interface{} `json:"err"`
|
||||
Fee int `json:"fee"`
|
||||
InnerInstructions []interface{} `json:"innerInstructions"`
|
||||
LogMessages []interface{} `json:"logMessages"`
|
||||
PostBalances []interface{} `json:"postBalances"`
|
||||
PreBalances []interface{} `json:"preBalances"`
|
||||
Status TxStatus `json:"status"`
|
||||
}
|
||||
type TxHeader struct {
|
||||
NumReadonlySignedAccounts int `json:"numReadonlySignedAccounts"`
|
||||
NumReadonlyUnsignedAccounts int `json:"numReadonlyUnsignedAccounts"`
|
||||
NumRequiredSignatures int `json:"numRequiredSignatures"`
|
||||
}
|
||||
type TxInstructions struct {
|
||||
Accounts []int `json:"accounts"`
|
||||
Data string `json:"data"`
|
||||
ProgramIDIndex int `json:"programIdIndex"`
|
||||
}
|
||||
type Message struct {
|
||||
AccountKeys []string `json:"accountKeys"`
|
||||
Header TxHeader `json:"header"`
|
||||
Instructions []TxInstructions `json:"instructions"`
|
||||
RecentBlockhash string `json:"recentBlockhash"`
|
||||
}
|
||||
type Transaction struct {
|
||||
Message Message `json:"message"`
|
||||
Signatures []string `json:"signatures"`
|
||||
}
|
||||
type TxResult struct {
|
||||
Meta TxMeta `json:"meta"`
|
||||
Slot int `json:"slot"`
|
||||
Transaction Transaction `json:"transaction"`
|
||||
}
|
@ -17,6 +17,17 @@ const (
|
||||
SigTypeEd25519 = SigType(iota)
|
||||
)
|
||||
|
||||
func (t SigType) Name() (string, error) {
|
||||
switch t {
|
||||
case SigTypeUnknown:
|
||||
return "unknown", nil
|
||||
case SigTypeEd25519:
|
||||
return "ed25519", nil
|
||||
default:
|
||||
return "", fmt.Errorf("invalid signature type: %d", t)
|
||||
}
|
||||
}
|
||||
|
||||
const SignatureMaxLength = 200
|
||||
|
||||
type Signature struct {
|
||||
|
@ -36,6 +36,31 @@ type DioneTask struct {
|
||||
Signature *Signature
|
||||
DrandRound DrandRound
|
||||
Payload []byte
|
||||
BlockHash string
|
||||
}
|
||||
|
||||
func NewDioneTask(
|
||||
t TaskType,
|
||||
miner peer.ID,
|
||||
ticket *Ticket,
|
||||
electionProof *ElectionProof,
|
||||
beacon []BeaconEntry,
|
||||
sig *Signature,
|
||||
drand DrandRound,
|
||||
payload []byte,
|
||||
blockHash string,
|
||||
) *DioneTask {
|
||||
return &DioneTask{
|
||||
Type: t,
|
||||
Miner: miner,
|
||||
Ticket: ticket,
|
||||
ElectionProof: electionProof,
|
||||
BeaconEntries: beacon,
|
||||
Signature: sig,
|
||||
DrandRound: drand,
|
||||
Payload: payload,
|
||||
BlockHash: blockHash,
|
||||
}
|
||||
}
|
||||
|
||||
var tasksPerEpoch = NewInt(config.TasksPerEpoch)
|
||||
|
@ -7,6 +7,7 @@ import (
|
||||
"github.com/libp2p/go-libp2p-core/peer"
|
||||
|
||||
"github.com/Secured-Finance/dione/sigs"
|
||||
_ "github.com/Secured-Finance/dione/sigs/ed25519" // enable ed25519 signatures
|
||||
"github.com/Secured-Finance/dione/types"
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/sirupsen/logrus"
|
||||
@ -107,11 +108,13 @@ func (w *LocalWallet) tryFind(addr peer.ID) (types.KeyInfo, error) {
|
||||
if err != nil {
|
||||
return types.KeyInfo{}, err
|
||||
}
|
||||
logrus.Info("tAddress: ", tAddress)
|
||||
|
||||
ki, err = w.keystore.Get(KNamePrefix + tAddress)
|
||||
if err != nil {
|
||||
return types.KeyInfo{}, err
|
||||
}
|
||||
logrus.Info("ki from tryFind: ", ki)
|
||||
|
||||
// We found it with the testnet prefix
|
||||
// Add this KeyInfo with the mainnet prefix address string
|
||||
|
Loading…
Reference in New Issue
Block a user