add: staking store db integration, task mining execution
This commit is contained in:
parent
9219e483a1
commit
239e54b0dd
@ -1,6 +1,8 @@
|
|||||||
package config
|
package config
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
"github.com/spf13/viper"
|
"github.com/spf13/viper"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -13,6 +15,7 @@ type Config struct {
|
|||||||
Ethereum EthereumConfig `mapstructure:"ethereum"`
|
Ethereum EthereumConfig `mapstructure:"ethereum"`
|
||||||
Filecoin FilecoinConfig `mapstructure:"filecoin"`
|
Filecoin FilecoinConfig `mapstructure:"filecoin"`
|
||||||
PubSub PubSubConfig `mapstructure:"pubSub"`
|
PubSub PubSubConfig `mapstructure:"pubSub"`
|
||||||
|
Store StoreConfig `mapstructure:"store"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type EthereumConfig struct {
|
type EthereumConfig struct {
|
||||||
@ -31,8 +34,17 @@ type PubSubConfig struct {
|
|||||||
ProtocolID string `mapstructure:"protocolID"`
|
ProtocolID string `mapstructure:"protocolID"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type StoreConfig struct {
|
||||||
|
DatabaseURL string `mapstructure:"database_url"`
|
||||||
|
}
|
||||||
|
|
||||||
// NewConfig creates a new config based on default values or provided .env file
|
// NewConfig creates a new config based on default values or provided .env file
|
||||||
func NewConfig(configPath string) (*Config, error) {
|
func NewConfig(configPath string) (*Config, error) {
|
||||||
|
dbName := "dione"
|
||||||
|
username := "user"
|
||||||
|
password := "password"
|
||||||
|
dbURL := fmt.Sprintf("host=localhost user=%s password=%s dbname=%s sslmode=disable", username, password, dbName)
|
||||||
|
|
||||||
cfg := &Config{
|
cfg := &Config{
|
||||||
ListenAddr: "localhost",
|
ListenAddr: "localhost",
|
||||||
ListenPort: ":8000",
|
ListenPort: ":8000",
|
||||||
@ -45,6 +57,9 @@ func NewConfig(configPath string) (*Config, error) {
|
|||||||
PubSub: PubSubConfig{
|
PubSub: PubSubConfig{
|
||||||
ProtocolID: "p2p-oracle",
|
ProtocolID: "p2p-oracle",
|
||||||
},
|
},
|
||||||
|
Store: StoreConfig{
|
||||||
|
DatabaseURL: dbURL,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
viper.SetConfigFile(configPath)
|
viper.SetConfigFile(configPath)
|
||||||
|
@ -13,18 +13,6 @@ import (
|
|||||||
"golang.org/x/xerrors"
|
"golang.org/x/xerrors"
|
||||||
)
|
)
|
||||||
|
|
||||||
type MinerWallet interface {
|
|
||||||
WalletSign(context.Context, address.Address, []byte) (*crypto.Signature, error)
|
|
||||||
}
|
|
||||||
|
|
||||||
type MinerBase struct {
|
|
||||||
MinerStake types.BigInt
|
|
||||||
NetworkStake types.BigInt
|
|
||||||
WorkerKey address.Address
|
|
||||||
PrevBeaconEntry types.BeaconEntry
|
|
||||||
BeaconEntries []types.BeaconEntry
|
|
||||||
}
|
|
||||||
|
|
||||||
type SignFunc func(context.Context, address.Address, []byte) (*crypto.Signature, error)
|
type SignFunc func(context.Context, address.Address, []byte) (*crypto.Signature, error)
|
||||||
|
|
||||||
func ComputeVRF(ctx context.Context, sign SignFunc, worker address.Address, sigInput []byte) ([]byte, error) {
|
func ComputeVRF(ctx context.Context, sign SignFunc, worker address.Address, sigInput []byte) ([]byte, error) {
|
||||||
@ -57,7 +45,7 @@ func VerifyVRF(ctx context.Context, worker address.Address, vrfBase, vrfproof []
|
|||||||
}
|
}
|
||||||
|
|
||||||
func IsRoundWinner(ctx context.Context, round types.TaskEpoch,
|
func IsRoundWinner(ctx context.Context, round types.TaskEpoch,
|
||||||
worker address.Address, brand types.BeaconEntry, mbi *MinerBase, a MinerWallet) (*types.ElectionProof, error) {
|
worker address.Address, brand types.BeaconEntry, mb *MinerBase, a MinerAPI) (*types.ElectionProof, error) {
|
||||||
|
|
||||||
buf := new(bytes.Buffer)
|
buf := new(bytes.Buffer)
|
||||||
if err := worker.MarshalCBOR(buf); err != nil {
|
if err := worker.MarshalCBOR(buf); err != nil {
|
||||||
@ -69,13 +57,13 @@ func IsRoundWinner(ctx context.Context, round types.TaskEpoch,
|
|||||||
return nil, xerrors.Errorf("failed to draw randomness: %w", err)
|
return nil, xerrors.Errorf("failed to draw randomness: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
vrfout, err := ComputeVRF(ctx, a.WalletSign, mbi.WorkerKey, electionRand)
|
vrfout, err := ComputeVRF(ctx, a.WalletSign, mb.WorkerKey, electionRand)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, xerrors.Errorf("failed to compute VRF: %w", err)
|
return nil, xerrors.Errorf("failed to compute VRF: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
ep := &types.ElectionProof{VRFProof: vrfout}
|
ep := &types.ElectionProof{VRFProof: vrfout}
|
||||||
j := ep.ComputeWinCount(mbi.MinerStake, mbi.NetworkStake)
|
j := ep.ComputeWinCount(mb.MinerStake, mb.NetworkStake)
|
||||||
ep.WinCount = j
|
ep.WinCount = j
|
||||||
if j < 1 {
|
if j < 1 {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
|
110
consensus/miner.go
Normal file
110
consensus/miner.go
Normal file
@ -0,0 +1,110 @@
|
|||||||
|
package consensus
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/Secured-Finance/dione/types"
|
||||||
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
"github.com/filecoin-project/go-address"
|
||||||
|
"github.com/filecoin-project/go-state-types/crypto"
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
|
"golang.org/x/xerrors"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Miner struct {
|
||||||
|
address address.Address
|
||||||
|
api MinerAPI
|
||||||
|
}
|
||||||
|
|
||||||
|
type MinerAPI interface {
|
||||||
|
WalletSign(context.Context, address.Address, []byte) (*crypto.Signature, error)
|
||||||
|
// TODO: get miner base based on epoch;
|
||||||
|
}
|
||||||
|
|
||||||
|
type MinerBase struct {
|
||||||
|
MinerStake types.BigInt
|
||||||
|
NetworkStake types.BigInt
|
||||||
|
WorkerKey address.Address
|
||||||
|
EthWallet common.Address
|
||||||
|
PrevBeaconEntry types.BeaconEntry
|
||||||
|
BeaconEntries []types.BeaconEntry
|
||||||
|
NullRounds types.TaskEpoch
|
||||||
|
}
|
||||||
|
|
||||||
|
type MiningBase struct {
|
||||||
|
epoch types.TaskEpoch
|
||||||
|
nullRounds types.TaskEpoch
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewMinerBase(minerStake, networkStake types.BigInt, minerWallet address.Address,
|
||||||
|
minerEthWallet common.Address, prev types.BeaconEntry, entries []types.BeaconEntry) *MinerBase {
|
||||||
|
return &MinerBase{
|
||||||
|
MinerStake: minerStake,
|
||||||
|
NetworkStake: networkStake,
|
||||||
|
WorkerKey: minerWallet,
|
||||||
|
EthWallet: minerEthWallet,
|
||||||
|
PrevBeaconEntry: prev,
|
||||||
|
BeaconEntries: entries,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewMiningBase() *MiningBase {
|
||||||
|
return &MiningBase{
|
||||||
|
nullRounds: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start, Stop mining functions
|
||||||
|
|
||||||
|
func (m *Miner) MineTask(ctx context.Context, base *MiningBase, mb *MinerBase) (*types.DioneTask, error) {
|
||||||
|
round := base.epoch + base.nullRounds + 1
|
||||||
|
logrus.Debug("attempting to mine the task at epoch: ", round)
|
||||||
|
|
||||||
|
prevEntry := mb.PrevBeaconEntry
|
||||||
|
|
||||||
|
ticket, err := m.computeTicket(ctx, &prevEntry, base, mb)
|
||||||
|
if err != nil {
|
||||||
|
return nil, xerrors.Errorf("scratching ticket failed: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
winner, err := IsRoundWinner(ctx, round, m.address, prevEntry, mb, m.api)
|
||||||
|
if err != nil {
|
||||||
|
return nil, xerrors.Errorf("failed to check if we win next round: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if winner == nil {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
return &types.DioneTask{
|
||||||
|
Miner: m.address,
|
||||||
|
Ticket: ticket,
|
||||||
|
ElectionProof: winner,
|
||||||
|
BeaconEntries: mb.BeaconEntries,
|
||||||
|
// TODO: signature
|
||||||
|
Height: round,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Miner) computeTicket(ctx context.Context, brand *types.BeaconEntry, base *MiningBase, mb *MinerBase) (*types.Ticket, error) {
|
||||||
|
buf := new(bytes.Buffer)
|
||||||
|
if err := m.address.MarshalCBOR(buf); err != nil {
|
||||||
|
return nil, xerrors.Errorf("failed to marshal address to cbor: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
round := base.epoch + base.nullRounds + 1
|
||||||
|
|
||||||
|
input, err := DrawRandomness(brand.Data, crypto.DomainSeparationTag_TicketProduction, round-types.TicketRandomnessLookback, buf.Bytes())
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
vrfOut, err := ComputeVRF(ctx, m.api.WalletSign, mb.WorkerKey, input)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &types.Ticket{
|
||||||
|
VRFProof: vrfOut,
|
||||||
|
}, nil
|
||||||
|
}
|
1
go.mod
1
go.mod
@ -21,6 +21,7 @@ require (
|
|||||||
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e // indirect
|
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e // indirect
|
||||||
github.com/google/uuid v1.1.1
|
github.com/google/uuid v1.1.1
|
||||||
github.com/gopherjs/gopherjs v0.0.0-20190812055157-5d271430af9f // indirect
|
github.com/gopherjs/gopherjs v0.0.0-20190812055157-5d271430af9f // indirect
|
||||||
|
github.com/jmoiron/sqlx v1.2.0
|
||||||
github.com/karalabe/usb v0.0.0-20191104083709-911d15fe12a9 // indirect
|
github.com/karalabe/usb v0.0.0-20191104083709-911d15fe12a9 // indirect
|
||||||
github.com/libp2p/go-libp2p v0.11.0
|
github.com/libp2p/go-libp2p v0.11.0
|
||||||
github.com/libp2p/go-libp2p-core v0.6.1
|
github.com/libp2p/go-libp2p-core v0.6.1
|
||||||
|
4
go.sum
4
go.sum
@ -680,6 +680,8 @@ github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M
|
|||||||
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
|
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
|
||||||
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
|
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
|
||||||
github.com/jmespath/go-jmespath v0.3.0/go.mod h1:9QtRXoHjLGCJ5IBSaohpXITPlowMeeYCZ7fLUTSywik=
|
github.com/jmespath/go-jmespath v0.3.0/go.mod h1:9QtRXoHjLGCJ5IBSaohpXITPlowMeeYCZ7fLUTSywik=
|
||||||
|
github.com/jmoiron/sqlx v1.2.0 h1:41Ip0zITnmWNR/vHV+S4m+VoUivnWY5E4OJfLZjCJMA=
|
||||||
|
github.com/jmoiron/sqlx v1.2.0/go.mod h1:1FEQNm3xlJgrMD+FBdI9+xvCksHtbpVBBw5dYhBSsks=
|
||||||
github.com/joeshaw/multierror v0.0.0-20140124173710-69b34d4ec901 h1:rp+c0RAYOWj8l6qbCUTSiRLG/iKnW3K3/QfPPuSsBt4=
|
github.com/joeshaw/multierror v0.0.0-20140124173710-69b34d4ec901 h1:rp+c0RAYOWj8l6qbCUTSiRLG/iKnW3K3/QfPPuSsBt4=
|
||||||
github.com/joeshaw/multierror v0.0.0-20140124173710-69b34d4ec901/go.mod h1:Z86h9688Y0wesXCyonoVr47MasHilkuLMqGhRZ4Hpak=
|
github.com/joeshaw/multierror v0.0.0-20140124173710-69b34d4ec901/go.mod h1:Z86h9688Y0wesXCyonoVr47MasHilkuLMqGhRZ4Hpak=
|
||||||
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
|
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
|
||||||
@ -730,6 +732,7 @@ github.com/kr/pty v1.1.3/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
|||||||
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
|
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
|
||||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||||
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
|
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
|
||||||
|
github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||||
github.com/lib/pq v1.7.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
|
github.com/lib/pq v1.7.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
|
||||||
github.com/libp2p/go-addr-util v0.0.1/go.mod h1:4ac6O7n9rIAKB1dnd+s8IbbMXkt+oBpzX4/+RACcnlQ=
|
github.com/libp2p/go-addr-util v0.0.1/go.mod h1:4ac6O7n9rIAKB1dnd+s8IbbMXkt+oBpzX4/+RACcnlQ=
|
||||||
github.com/libp2p/go-addr-util v0.0.2 h1:7cWK5cdA5x72jX0g8iLrQWm5TRJZ6CzGdPEhWj7plWU=
|
github.com/libp2p/go-addr-util v0.0.2 h1:7cWK5cdA5x72jX0g8iLrQWm5TRJZ6CzGdPEhWj7plWU=
|
||||||
@ -1075,6 +1078,7 @@ github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Ky
|
|||||||
github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
|
github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
|
||||||
github.com/mattn/go-runewidth v0.0.7 h1:Ei8KR0497xHyKJPAv59M1dkC+rOZCMBJ+t3fZ+twI54=
|
github.com/mattn/go-runewidth v0.0.7 h1:Ei8KR0497xHyKJPAv59M1dkC+rOZCMBJ+t3fZ+twI54=
|
||||||
github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
|
github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
|
||||||
|
github.com/mattn/go-sqlite3 v1.9.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
|
||||||
github.com/mattn/go-xmlrpc v0.0.3/go.mod h1:mqc2dz7tP5x5BKlCahN/n+hs7OSZKJkS9JsHNBRlrxA=
|
github.com/mattn/go-xmlrpc v0.0.3/go.mod h1:mqc2dz7tP5x5BKlCahN/n+hs7OSZKJkS9JsHNBRlrxA=
|
||||||
github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=
|
github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=
|
||||||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
||||||
|
@ -17,6 +17,7 @@ import (
|
|||||||
// TODO: change artifacts for other contracts
|
// TODO: change artifacts for other contracts
|
||||||
type EthereumClient struct {
|
type EthereumClient struct {
|
||||||
client *ethclient.Client
|
client *ethclient.Client
|
||||||
|
ethAddress *common.Address
|
||||||
authTransactor *bind.TransactOpts
|
authTransactor *bind.TransactOpts
|
||||||
oracleEmitter *oracleemitter.OracleEmitterSession
|
oracleEmitter *oracleemitter.OracleEmitterSession
|
||||||
aggregator *aggregator.AggregatorSession
|
aggregator *aggregator.AggregatorSession
|
||||||
@ -53,6 +54,7 @@ func (c *EthereumClient) Initialize(ctx context.Context, url, privateKey, oracle
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
c.ethAddress = &c.authTransactor.From
|
||||||
authTransactor := bind.NewKeyedTransactor(ecdsaKey)
|
authTransactor := bind.NewKeyedTransactor(ecdsaKey)
|
||||||
c.authTransactor = authTransactor
|
c.authTransactor = authTransactor
|
||||||
|
|
||||||
@ -158,26 +160,6 @@ func (c *EthereumClient) Initialize(ctx context.Context, url, privateKey, oracle
|
|||||||
// return TxHash
|
// return TxHash
|
||||||
// }
|
// }
|
||||||
|
|
||||||
// func (c *EthereumClient) GenerateAddressFromPrivateKey(private_key string) string {
|
|
||||||
// privateKey, err := crypto.HexToECDSA(private_key)
|
|
||||||
// if err != nil {
|
|
||||||
// c.Logger.Fatal("Failed to generate private key", err)
|
|
||||||
// }
|
|
||||||
|
|
||||||
// publicKey := privateKey.Public()
|
|
||||||
// publicKeyECDSA, ok := publicKey.(*ecdsa.PublicKey)
|
|
||||||
// if !ok {
|
|
||||||
// c.Logger.Fatal("cannot assert type: publicKey is not of type *ecdsa.PublicKey")
|
|
||||||
// }
|
|
||||||
|
|
||||||
// publicKeyBytes := crypto.FromECDSAPub(publicKeyECDSA)
|
|
||||||
// c.Logger.Info(hexutil.Encode(publicKeyBytes)[4:])
|
|
||||||
|
|
||||||
// address := crypto.PubkeyToAddress(*publicKeyECDSA).Hex()
|
|
||||||
|
|
||||||
// return address
|
|
||||||
// }
|
|
||||||
|
|
||||||
func (c *EthereumClient) SubscribeOnOracleEvents(incomingEventsChan chan *oracleemitter.OracleEmitterNewOracleRequest) (event.Subscription, error) {
|
func (c *EthereumClient) SubscribeOnOracleEvents(incomingEventsChan chan *oracleemitter.OracleEmitterNewOracleRequest) (event.Subscription, error) {
|
||||||
requestsFilter := c.oracleEmitter.Contract.OracleEmitterFilterer
|
requestsFilter := c.oracleEmitter.Contract.OracleEmitterFilterer
|
||||||
subscription, err := requestsFilter.WatchNewOracleRequest(&bind.WatchOpts{
|
subscription, err := requestsFilter.WatchNewOracleRequest(&bind.WatchOpts{
|
||||||
@ -224,6 +206,9 @@ func (c *EthereumClient) SubmitRequestAnswer(reqID *big.Int, data string, callba
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Getting total stake in DioneStaking contract, this function could
|
||||||
|
// be used for storing the total stake and veryfing the stake tokens
|
||||||
|
// on new tasks
|
||||||
func (c *EthereumClient) GetTotalStake() (*big.Int, error) {
|
func (c *EthereumClient) GetTotalStake() (*big.Int, error) {
|
||||||
totalStake, err := c.dioneStaking.TotalStake()
|
totalStake, err := c.dioneStaking.TotalStake()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -232,6 +217,9 @@ func (c *EthereumClient) GetTotalStake() (*big.Int, error) {
|
|||||||
return totalStake, nil
|
return totalStake, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Getting miner stake in DioneStaking contract, this function could
|
||||||
|
// be used for storing the miner's stake and veryfing the stake tokens
|
||||||
|
// on new tasks
|
||||||
func (c *EthereumClient) GetMinerStake(minerAddress common.Address) (*big.Int, error) {
|
func (c *EthereumClient) GetMinerStake(minerAddress common.Address) (*big.Int, error) {
|
||||||
minerStake, err := c.dioneStaking.MinerStake(minerAddress)
|
minerStake, err := c.dioneStaking.MinerStake(minerAddress)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
35
rpcclient/wallet.go
Normal file
35
rpcclient/wallet.go
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
package rpcclient
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/ecdsa"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||||
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
|
)
|
||||||
|
|
||||||
|
func GenerateEthWalletAddressFromPrivateKey(private_key string) common.Address {
|
||||||
|
privateKey, err := crypto.HexToECDSA(private_key)
|
||||||
|
if err != nil {
|
||||||
|
logrus.Fatal("Failed to generate private key", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
publicKey := privateKey.Public()
|
||||||
|
publicKeyECDSA, ok := publicKey.(*ecdsa.PublicKey)
|
||||||
|
if !ok {
|
||||||
|
logrus.Fatal("cannot assert type: publicKey is not of type *ecdsa.PublicKey")
|
||||||
|
}
|
||||||
|
|
||||||
|
publicKeyBytes := crypto.FromECDSAPub(publicKeyECDSA)
|
||||||
|
logrus.Info(hexutil.Encode(publicKeyBytes)[4:])
|
||||||
|
|
||||||
|
address := crypto.PubkeyToAddress(*publicKeyECDSA)
|
||||||
|
|
||||||
|
return address
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert common.Address type into string for ethereum wallet
|
||||||
|
func EthWalletToString(ethWallet common.Address) string {
|
||||||
|
return ethWallet.Hex()
|
||||||
|
}
|
@ -2,28 +2,37 @@ package store
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"math/big"
|
"math/big"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/Secured-Finance/dione/lib"
|
||||||
"github.com/Secured-Finance/dione/rpcclient"
|
"github.com/Secured-Finance/dione/rpcclient"
|
||||||
|
"github.com/Secured-Finance/dione/types"
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
validation "github.com/go-ozzo/ozzo-validation"
|
||||||
)
|
)
|
||||||
|
|
||||||
// TODO: specify store for staking mechanism
|
|
||||||
type DioneStakeInfo struct {
|
type DioneStakeInfo struct {
|
||||||
MinerStake *big.Int
|
ID int
|
||||||
TotalStake *big.Int
|
MinerStake *big.Int
|
||||||
Ethereum *rpcclient.EthereumClient
|
TotalStake *big.Int
|
||||||
|
MinerWallet string
|
||||||
|
MinerEthWallet string
|
||||||
|
Timestamp time.Time
|
||||||
|
Ethereum *rpcclient.EthereumClient
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewDioneStakeInfo(minerStake, totalStake *big.Int, ethereumClient *rpcclient.EthereumClient) *DioneStakeInfo {
|
func NewDioneStakeInfo(minerStake, totalStake *big.Int, minerWallet, minerEthWallet string, ethereumClient *rpcclient.EthereumClient) *DioneStakeInfo {
|
||||||
return &DioneStakeInfo{
|
return &DioneStakeInfo{
|
||||||
MinerStake: minerStake,
|
MinerStake: minerStake,
|
||||||
TotalStake: totalStake,
|
TotalStake: totalStake,
|
||||||
Ethereum: ethereumClient,
|
MinerWallet: minerWallet,
|
||||||
|
MinerEthWallet: minerEthWallet,
|
||||||
|
Ethereum: ethereumClient,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *DioneStakeInfo) UpdateMinerStake(minerAddress common.Address) error {
|
func (d *DioneStakeInfo) UpdateMinerStake(minerEthAddress common.Address) error {
|
||||||
minerStake, err := d.Ethereum.GetMinerStake(minerAddress)
|
minerStake, err := d.Ethereum.GetMinerStake(minerEthAddress)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -33,7 +42,7 @@ func (d *DioneStakeInfo) UpdateMinerStake(minerAddress common.Address) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *DioneStakeInfo) UpdateTotalStake(minerAddress common.Address) error {
|
func (d *DioneStakeInfo) UpdateTotalStake() error {
|
||||||
totalStake, err := d.Ethereum.GetTotalStake()
|
totalStake, err := d.Ethereum.GetTotalStake()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -43,3 +52,46 @@ func (d *DioneStakeInfo) UpdateTotalStake(minerAddress common.Address) error {
|
|||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Put miner's staking information into the database
|
||||||
|
func (s *Store) CreateDioneStakeInfo(stakeStore *DioneStakeInfo) error {
|
||||||
|
|
||||||
|
if err := stakeStore.Validate(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
now := lib.Clock.Now()
|
||||||
|
|
||||||
|
return s.db.QueryRow(
|
||||||
|
"INSERT INTO staking (miner_stake, total_stake, miner_wallet, miner_eth_wallet, timestamp) VALUES ($1, $2, $3, $4, $5) RETURNING id",
|
||||||
|
stakeStore.MinerStake,
|
||||||
|
stakeStore.TotalStake,
|
||||||
|
stakeStore.MinerWallet,
|
||||||
|
stakeStore.MinerEthWallet,
|
||||||
|
now,
|
||||||
|
).Scan(&stakeStore.ID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Store) GetLastStakeInfo(wallet, ethWallet string) (*DioneStakeInfo, error) {
|
||||||
|
var stake *DioneStakeInfo
|
||||||
|
if err := s.db.Select(&stake,
|
||||||
|
`SELECT miner_stake, total_stake, miner_wallet, miner_eth_wallet, timestamp FROM staking ORDER BY TIMESTAMP DESC LIMIT 1 WHERE miner_wallet=$1, miner_eth_wallet=$2`,
|
||||||
|
wallet,
|
||||||
|
ethWallet,
|
||||||
|
); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return stake, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Before puting the data into the database validating all required fields
|
||||||
|
func (s *DioneStakeInfo) Validate() error {
|
||||||
|
return validation.ValidateStruct(
|
||||||
|
s,
|
||||||
|
validation.Field(&s.MinerStake, validation.Required, validation.By(types.ValidateBigInt(s.MinerStake))),
|
||||||
|
validation.Field(&s.TotalStake, validation.Required, validation.By(types.ValidateBigInt(s.TotalStake))),
|
||||||
|
validation.Field(&s.MinerWallet, validation.Required),
|
||||||
|
validation.Field(&s.MinerEthWallet, validation.Required),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
@ -1,24 +1,45 @@
|
|||||||
package store
|
package store
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"database/sql"
|
|
||||||
|
|
||||||
"github.com/Secured-Finance/dione/node"
|
"github.com/Secured-Finance/dione/node"
|
||||||
|
"github.com/jmoiron/sqlx"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Store struct {
|
type Store struct {
|
||||||
db *sql.DB
|
db *sqlx.DB
|
||||||
node *node.Node
|
node *node.Node
|
||||||
genesisTs uint64
|
genesisTs uint64
|
||||||
|
StakeStorage DioneStakeInfo
|
||||||
// genesisTask *types.DioneTask
|
// genesisTask *types.DioneTask
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewStore(db *sql.DB, node *node.Node, genesisTs uint64) *Store {
|
func NewStore(node *node.Node, genesisTs uint64) (*Store, error) {
|
||||||
|
db, err := newDB(node.Config.Store.DatabaseURL)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
defer db.Close()
|
||||||
|
|
||||||
return &Store{
|
return &Store{
|
||||||
db: db,
|
db: db,
|
||||||
node: node,
|
node: node,
|
||||||
genesisTs: genesisTs,
|
genesisTs: genesisTs,
|
||||||
}
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: connect data base; specify the table for stake storage; queries for stake storage
|
func newDB(databaseURL string) (*sqlx.DB, error) {
|
||||||
|
db, err := sqlx.Connect("postgres", databaseURL)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := db.Ping(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return db, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Discuss with ChronosX88 about using custom database to decrease I/O bound
|
||||||
|
// specify the migrations for stake storage;
|
||||||
|
@ -1,9 +1,11 @@
|
|||||||
package types
|
package types
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"math/big"
|
"math/big"
|
||||||
|
|
||||||
big2 "github.com/filecoin-project/go-state-types/big"
|
big2 "github.com/filecoin-project/go-state-types/big"
|
||||||
|
validation "github.com/go-ozzo/ozzo-validation"
|
||||||
)
|
)
|
||||||
|
|
||||||
var EmptyInt = BigInt{}
|
var EmptyInt = BigInt{}
|
||||||
@ -18,3 +20,13 @@ func BigFromBytes(b []byte) BigInt {
|
|||||||
i := big.NewInt(0).SetBytes(b)
|
i := big.NewInt(0).SetBytes(b)
|
||||||
return BigInt{Int: i}
|
return BigInt{Int: i}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func ValidateBigInt(i *big.Int) validation.RuleFunc {
|
||||||
|
return func(value interface{}) error {
|
||||||
|
bigInt := i.IsInt64()
|
||||||
|
if !bigInt {
|
||||||
|
return errors.New("expected big integer")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -11,6 +11,8 @@ import (
|
|||||||
// TaskEpoch represents the timestamp of Task computed by the Dione miner
|
// TaskEpoch represents the timestamp of Task computed by the Dione miner
|
||||||
type TaskEpoch int64
|
type TaskEpoch int64
|
||||||
|
|
||||||
|
const TicketRandomnessLookback = TaskEpoch(1)
|
||||||
|
|
||||||
func (e TaskEpoch) String() string {
|
func (e TaskEpoch) String() string {
|
||||||
return strconv.FormatInt(int64(e), 10)
|
return strconv.FormatInt(int64(e), 10)
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user