diff --git a/examples/democoin/app/app.go b/examples/democoin/app/app.go index a27a37cebe..27ca7a1458 100644 --- a/examples/democoin/app/app.go +++ b/examples/democoin/app/app.go @@ -80,6 +80,7 @@ func NewDemocoinApp(logger log.Logger, dbs map[string]dbm.DB) *DemocoinApp { app.SetInitChainer(app.initChainerFn(coolKeeper)) app.MountStoreWithDB(app.capKeyMainStore, sdk.StoreTypeIAVL, dbs["main"]) app.MountStoreWithDB(app.capKeyAccountStore, sdk.StoreTypeIAVL, dbs["acc"]) + app.MountStoreWithDB(app.capKeyPowStore, sdk.StoreTypeIAVL, dbs["pow"]) app.MountStoreWithDB(app.capKeyIBCStore, sdk.StoreTypeIAVL, dbs["ibc"]) app.MountStoreWithDB(app.capKeyStakingStore, sdk.StoreTypeIAVL, dbs["staking"]) // NOTE: Broken until #532 lands @@ -100,16 +101,18 @@ func MakeCodec() *wire.Codec { const msgTypeIssue = 0x2 const msgTypeQuiz = 0x3 const msgTypeSetTrend = 0x4 - const msgTypeIBCTransferMsg = 0x5 - const msgTypeIBCReceiveMsg = 0x6 - const msgTypeBondMsg = 0x7 - const msgTypeUnbondMsg = 0x8 + const msgTypeMine = 0x5 + const msgTypeIBCTransferMsg = 0x6 + const msgTypeIBCReceiveMsg = 0x7 + const msgTypeBondMsg = 0x8 + const msgTypeUnbondMsg = 0x9 var _ = oldwire.RegisterInterface( struct{ sdk.Msg }{}, oldwire.ConcreteType{bank.SendMsg{}, msgTypeSend}, oldwire.ConcreteType{bank.IssueMsg{}, msgTypeIssue}, oldwire.ConcreteType{cool.QuizMsg{}, msgTypeQuiz}, oldwire.ConcreteType{cool.SetTrendMsg{}, msgTypeSetTrend}, + oldwire.ConcreteType{pow.MineMsg{}, msgTypeMine}, oldwire.ConcreteType{ibc.IBCTransferMsg{}, msgTypeIBCTransferMsg}, oldwire.ConcreteType{ibc.IBCReceiveMsg{}, msgTypeIBCReceiveMsg}, oldwire.ConcreteType{simplestake.BondMsg{}, msgTypeBondMsg}, diff --git a/examples/democoin/app/app_test.go b/examples/democoin/app/app_test.go index bf2ddc232f..74b789bea0 100644 --- a/examples/democoin/app/app_test.go +++ b/examples/democoin/app/app_test.go @@ -11,6 +11,7 @@ import ( "github.com/cosmos/cosmos-sdk/examples/democoin/types" "github.com/cosmos/cosmos-sdk/examples/democoin/x/cool" + "github.com/cosmos/cosmos-sdk/examples/democoin/x/pow" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/auth" "github.com/cosmos/cosmos-sdk/x/bank" @@ -71,6 +72,7 @@ func loggerAndDBs() (log.Logger, map[string]dbm.DB) { dbs := map[string]dbm.DB{ "main": dbm.NewMemDB(), "acc": dbm.NewMemDB(), + "pow": dbm.NewMemDB(), "ibc": dbm.NewMemDB(), "staking": dbm.NewMemDB(), } @@ -238,6 +240,53 @@ func TestSendMsgWithAccounts(t *testing.T) { assert.Equal(t, sdk.CodeOK, res.Code, res.Log) } +func TestMineMsg(t *testing.T) { + bapp := newDemocoinApp() + + // Construct genesis state + // Construct some genesis bytes to reflect democoin/types/AppAccount + coins := sdk.Coins{} + baseAcc := auth.BaseAccount{ + Address: addr1, + Coins: coins, + } + acc1 := &types.AppAccount{baseAcc, "foobart"} + + // Construct genesis state + genesisState := map[string]interface{}{ + "accounts": []*types.GenesisAccount{ + types.NewGenesisAccount(acc1), + }, + "cool": map[string]string{ + "trend": "ice-cold", + }, + } + stateBytes, err := json.MarshalIndent(genesisState, "", "\t") + require.Nil(t, err) + + // Initialize the chain (nil) + vals := []abci.Validator{} + bapp.InitChain(abci.RequestInitChain{vals, stateBytes}) + bapp.Commit() + + // A checkTx context (true) + ctxCheck := bapp.BaseApp.NewContext(true, abci.Header{}) + res1 := bapp.accountMapper.GetAccount(ctxCheck, addr1) + assert.Equal(t, acc1, res1) + + // Mine and check for reward + mineMsg1 := pow.GenerateMineMsg(addr1, 1, 2) + SignCheckDeliver(t, bapp, mineMsg1, 0, true) + CheckBalance(t, bapp, "1pow") + // Mine again and check for reward + /* + mineMsg2 := pow.GenerateMineMsg(addr1, 2, 2) + SignCheckDeliver(t, bapp, mineMsg2, 1, true) + CheckBalance(t, bapp, "2pow") + */ + +} + func TestQuizMsg(t *testing.T) { bapp := newDemocoinApp() diff --git a/examples/democoin/cmd/democoind/main.go b/examples/democoin/cmd/democoind/main.go index 6fc5930678..3967747043 100644 --- a/examples/democoin/cmd/democoind/main.go +++ b/examples/democoin/cmd/democoind/main.go @@ -55,6 +55,10 @@ func generateApp(rootDir string, logger log.Logger) (abci.Application, error) { if err != nil { return nil, err } + dbPow, err := dbm.NewGoLevelDB("democoin-pow", filepath.Join(rootDir, "data")) + if err != nil { + return nil, err + } dbIBC, err := dbm.NewGoLevelDB("democoin-ibc", filepath.Join(rootDir, "data")) if err != nil { return nil, err @@ -66,6 +70,7 @@ func generateApp(rootDir string, logger log.Logger) (abci.Application, error) { dbs := map[string]dbm.DB{ "main": dbMain, "acc": dbAcc, + "pow": dbPow, "ibc": dbIBC, "staking": dbStaking, } diff --git a/examples/democoin/x/pow/mine.go b/examples/democoin/x/pow/mine.go new file mode 100644 index 0000000000..ff2264aaa7 --- /dev/null +++ b/examples/democoin/x/pow/mine.go @@ -0,0 +1,44 @@ +package pow + +import ( + "encoding/hex" + "math" + "strconv" + + sdk "github.com/cosmos/cosmos-sdk/types" + crypto "github.com/tendermint/go-crypto" +) + +func GenerateMineMsg(sender sdk.Address, count uint64, difficulty uint64) MineMsg { + nonce, hash := mine(sender, count, difficulty) + return NewMineMsg(sender, difficulty, count, nonce, hash) +} + +func hash(sender sdk.Address, count uint64, nonce uint64) []byte { + var bytes []byte + bytes = append(bytes, []byte(sender)...) + countBytes := strconv.FormatUint(count, 16) + bytes = append(bytes, countBytes...) + nonceBytes := strconv.FormatUint(nonce, 16) + bytes = append(bytes, nonceBytes...) + hash := crypto.Sha256(bytes) + // uint64, so we just use the first 8 bytes of the hash + // this limits the range of possible difficulty values (as compared to uint256), but fine for proof-of-concept + ret := make([]byte, hex.EncodedLen(len(hash))) + hex.Encode(ret, hash) + return ret[:16] +} + +func mine(sender sdk.Address, count uint64, difficulty uint64) (uint64, []byte) { + target := math.MaxUint64 / difficulty + for nonce := uint64(0); ; nonce++ { + hash := hash(sender, count, nonce) + hashuint, err := strconv.ParseUint(string(hash), 16, 64) + if err != nil { + panic(err) + } + if hashuint < target { + return nonce, hash + } + } +} diff --git a/examples/democoin/x/pow/types.go b/examples/democoin/x/pow/types.go index 70c456d840..ea368c3063 100644 --- a/examples/democoin/x/pow/types.go +++ b/examples/democoin/x/pow/types.go @@ -22,12 +22,15 @@ type MineMsg struct { Proof []byte `json:"proof"` } +// enforce the msg type at compile time +var _ sdk.Msg = MineMsg{} + // NewMineMsg - construct mine message func NewMineMsg(sender sdk.Address, difficulty uint64, count uint64, nonce uint64, proof []byte) MineMsg { return MineMsg{sender, difficulty, count, nonce, proof} } -func (msg MineMsg) Type() string { return "mine" } +func (msg MineMsg) Type() string { return "pow" } func (msg MineMsg) Get(key interface{}) (value interface{}) { return nil } func (msg MineMsg) GetSigners() []sdk.Address { return []sdk.Address{msg.Sender} } func (msg MineMsg) String() string { diff --git a/examples/democoin/x/pow/types_test.go b/examples/democoin/x/pow/types_test.go index 04360c3fda..34ab8914eb 100644 --- a/examples/democoin/x/pow/types_test.go +++ b/examples/democoin/x/pow/types_test.go @@ -1,16 +1,12 @@ package pow import ( - "encoding/hex" "fmt" - "math" - "strconv" "testing" "github.com/stretchr/testify/assert" sdk "github.com/cosmos/cosmos-sdk/types" - crypto "github.com/tendermint/go-crypto" ) func TestNewMineMsg(t *testing.T) { @@ -23,36 +19,7 @@ func TestNewMineMsg(t *testing.T) { func TestMineMsgType(t *testing.T) { addr := sdk.Address([]byte("sender")) msg := MineMsg{addr, 0, 0, 0, []byte("")} - assert.Equal(t, msg.Type(), "mine") -} - -func hash(sender sdk.Address, count uint64, nonce uint64) []byte { - var bytes []byte - bytes = append(bytes, []byte(sender)...) - countBytes := strconv.FormatUint(count, 16) - bytes = append(bytes, countBytes...) - nonceBytes := strconv.FormatUint(nonce, 16) - bytes = append(bytes, nonceBytes...) - hash := crypto.Sha256(bytes) - // uint64, so we just use the first 8 bytes of the hash - // this limits the range of possible difficulty values (as compared to uint256), but fine for proof-of-concept - ret := make([]byte, hex.EncodedLen(len(hash))) - hex.Encode(ret, hash) - return ret[:16] -} - -func mine(sender sdk.Address, count uint64, difficulty uint64) (uint64, []byte) { - target := math.MaxUint64 / difficulty - for nonce := uint64(0); ; nonce++ { - hash := hash(sender, count, nonce) - hashuint, err := strconv.ParseUint(string(hash), 16, 64) - if err != nil { - panic(err) - } - if hashuint < target { - return nonce, hash - } - } + assert.Equal(t, msg.Type(), "pow") } func TestMineMsgValidation(t *testing.T) {