Skip to content

Commit

Permalink
Merge pull request #30 from regen-network/27-claim_module
Browse files Browse the repository at this point in the history
#27 Create claim module
  • Loading branch information
aaronc authored Apr 25, 2019
2 parents ffc6261 + 869ef9a commit da1c1f0
Show file tree
Hide file tree
Showing 16 changed files with 615 additions and 60 deletions.
3 changes: 3 additions & 0 deletions cmd/xrncli/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import (
espclient "github.com/regen-network/regen-ledger/x/esp/client"
geoclient "github.com/regen-network/regen-ledger/x/geo/client"
agentclient "github.com/regen-network/regen-ledger/x/group/client"
claimclient "github.com/regen-network/regen-ledger/x/claim/client"
proposalclient "github.com/regen-network/regen-ledger/x/proposal/client"
upgradecli "github.com/regen-network/regen-ledger/x/upgrade/client/cli"
upgraderest "github.com/regen-network/regen-ledger/x/upgrade/client/rest"
Expand All @@ -37,6 +38,7 @@ import (

const (
storeAcc = "acc"
storeClaim = "claim"
storeData = "data"
storeAgent = "group"
storeProposal = "proposal"
Expand All @@ -61,6 +63,7 @@ func main() {
dataclient.NewModuleClient(storeData, cdc),
agentclient.NewModuleClient(storeAgent, cdc),
consortiumclient.NewModuleClient(cdc),
claimclient.NewModuleClient(storeClaim, cdc),
}

rootCmd := &cobra.Command{
Expand Down
23 changes: 23 additions & 0 deletions types/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,3 +80,26 @@ func DecodeBech32DataAddress(url string) (DataAddress, error) {
}
return nil, fmt.Errorf("can't decode data URL")
}

// IsGraphDataAddress indicates whether the provided DataAddress points to graph
// data - which has a well-known structure conformant with the schema module -
// as opposed to "raw" data which can have any format
func IsGraphDataAddress(addr DataAddress) bool {
switch addr[0] {
case DataAddressPrefixOnChainGraph:
return true
default:
return false
}
}

// IsRawDataAddress indicates whether the provided DataAddress points to raw
// data - i.e. data in any format - as opposed to well-structured graph data
func IsRawDataAddress(addr DataAddress) bool {
switch addr[0] {
case DataAddressPrefixOnChainGraph:
return false
default:
return false
}
}
30 changes: 30 additions & 0 deletions util/test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package util

import (
"github.com/cosmos/cosmos-sdk/codec"
"github.com/cosmos/cosmos-sdk/store"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/stretchr/testify/suite"
abci "github.com/tendermint/tendermint/abci/types"
dbm "github.com/tendermint/tendermint/libs/db"
"github.com/tendermint/tendermint/libs/log"
)

type TestHarness struct {
suite.Suite
Ctx sdk.Context
Cms store.CommitMultiStore
Cdc *codec.Codec
Db *dbm.MemDB
Addr1 sdk.AccAddress
Addr2 sdk.AccAddress
}

func (s *TestHarness) Setup() {
s.Db = dbm.NewMemDB()
s.Cms = store.NewCommitMultiStore(s.Db)
s.Cdc = codec.New()
s.Ctx = sdk.NewContext(s.Cms, abci.Header{}, false, log.NewNopLogger())
s.Addr1 = sdk.AccAddress{0, 1, 2, 3, 4, 5, 6, 7, 8}
s.Addr2 = sdk.AccAddress{1, 2, 3, 4, 5, 6, 7, 8, 9}
}
126 changes: 126 additions & 0 deletions x/claim/claim_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
package claim_test

import (
"bytes"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/regen-network/regen-ledger/graph"
"github.com/regen-network/regen-ledger/graph/binary"
"github.com/regen-network/regen-ledger/graph/gen"
"github.com/regen-network/regen-ledger/types"
"github.com/regen-network/regen-ledger/x/claim"
"github.com/regen-network/regen-ledger/x/data"
schema_test "github.com/regen-network/regen-ledger/x/schema/test"
"github.com/stretchr/testify/suite"
"testing"
)

type Suite struct {
schema_test.Harness
dataKeeper data.Keeper
Keeper claim.Keeper
Handler sdk.Handler
}

func (s *Suite) SetupTest() {
s.Setup()
data.RegisterCodec(s.Cdc)
claim.RegisterCodec(s.Cdc)
dataKey := sdk.NewKVStoreKey("data")
s.dataKeeper = data.NewKeeper(dataKey, s.Harness.Keeper, s.Cdc)
claimKey := sdk.NewKVStoreKey("claim")
s.Keeper = claim.NewKeeper(claimKey, s.dataKeeper, s.Cdc)
s.Handler = claim.NewHandler(s.Keeper)
s.Cms.MountStoreWithDB(dataKey, sdk.StoreTypeIAVL, s.Db)
s.Cms.MountStoreWithDB(claimKey, sdk.StoreTypeIAVL, s.Db)
_ = s.Cms.LoadLatestVersion()
s.CreateSampleSchema()
}

func (s *Suite) randomData() types.DataAddress {
x, ok := gen.Graph(s.Resolver).Sample()
if !ok {
panic("couldn't generate graph")
}
g := x.(graph.Graph)
buf := new(bytes.Buffer)
err := binary.SerializeGraph(s.Harness.Resolver, g, buf)
s.Require().Nil(err)
addr, err := s.dataKeeper.StoreGraph(s.Ctx, graph.Hash(g), buf.Bytes())
s.Require().Nil(err)
return addr
}

func (s *Suite) TestCreateClaim() {
s.T().Logf("sign a claim")
c := s.randomData()
ev0 := s.randomData()
ev1 := s.randomData()
msg := claim.MsgSignClaim{Content: c, Evidence: []types.DataAddress{ev0, ev1}, Signers: []sdk.AccAddress{s.Addr1}}
res := s.Handler(s.Ctx, msg)
s.Require().Equal(sdk.CodeOK, res.Code)
s.Require().Equal(string(res.Tags[0].Value), c.String())

s.T().Logf("retrieve the signatures")
sigs := s.Keeper.GetSigners(s.Ctx, c)
s.Require().True(bytes.Equal(s.Addr1, sigs[0]))

s.T().Logf("retrieve the evidence")
ev := s.Keeper.GetEvidence(s.Ctx, c, s.Addr1)
s.requireContainsData(ev, ev0)
s.requireContainsData(ev, ev1)

s.T().Logf("add more evidence and another signature")
ev2 := s.randomData()
err := s.Keeper.SignClaim(s.Ctx, c, []types.DataAddress{ev2}, []sdk.AccAddress{s.Addr1, s.Addr2})
s.Require().Nil(err)

s.T().Logf("retrieve the signatures")
sigs = s.Keeper.GetSigners(s.Ctx, c)
s.requireContainsAddr(sigs, s.Addr1)
s.requireContainsAddr(sigs, s.Addr2)

s.T().Logf("retrieve the evidence")
ev = s.Keeper.GetEvidence(s.Ctx, c, s.Addr1)
s.requireContainsData(ev, ev0)
s.requireContainsData(ev, ev1)
s.requireContainsData(ev, ev2)

ev = s.Keeper.GetEvidence(s.Ctx, c, s.Addr2)
s.requireContainsData(ev, ev2)
}

func (s *Suite) TestCreateBadClaim() {
msg := claim.MsgSignClaim{Signers: []sdk.AccAddress{s.Addr1}}
err := msg.ValidateBasic()
s.Require().NotNil(err)

msg = claim.MsgSignClaim{Content: types.GetDataAddressOnChainGraph([]byte{}), Signers: []sdk.AccAddress{s.Addr1}}
res := s.Handler(s.Ctx, msg)
s.Require().Equal(sdk.CodeUnknownRequest, res.Code)

msg = claim.MsgSignClaim{Content: types.DataAddress([]byte{10, 2, 3, 4}), Signers: []sdk.AccAddress{s.Addr1}}
res = s.Handler(s.Ctx, msg)
s.Require().Equal(sdk.CodeUnknownRequest, res.Code)
}

func (s *Suite) requireContainsAddr(xs []sdk.AccAddress, x sdk.AccAddress) {
for _, y := range xs {
if bytes.Equal(x, y) {
return
}
}
s.Require().FailNow("can't find address")
}

func (s *Suite) requireContainsData(xs []types.DataAddress, x types.DataAddress) {
for _, y := range xs {
if bytes.Equal(x, y) {
return
}
}
s.Require().FailNow("can't find the data")
}

func TestSuite(t *testing.T) {
suite.Run(t, new(Suite))
}
98 changes: 98 additions & 0 deletions x/claim/client/cli/query.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
package cli

import (
"fmt"
"github.com/cosmos/cosmos-sdk/client/context"
"github.com/cosmos/cosmos-sdk/codec"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/regen-network/regen-ledger/types"
"github.com/regen-network/regen-ledger/x/claim"
"github.com/spf13/cobra"
"strings"
)

// GetSignaturesQueryCmd creates a query sub-command for the claim module using cmdName as the name of the sub-command.
func GetSignaturesQueryCmd(storeName string, cdc *codec.Codec) *cobra.Command {
return &cobra.Command{
Use: "signatures <content-address>",
Short: "get signatures for claim",
Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
cliCtx := context.NewCLIContext().WithCodec(cdc)
content, err := types.DecodeBech32DataAddress(args[0])
if err != nil {
return err
}

res, err := cliCtx.QueryStore(claim.KeySignatures(content), storeName)
if err != nil {
return err
}

if len(res) == 0 {
return fmt.Errorf("no signatures for claim")
}

var sigs []sdk.AccAddress
err = cdc.UnmarshalBinaryBare(res, &sigs)
if err != nil {
return err
}

var signatures strings.Builder
for _, sig := range sigs {
signatures.WriteString(sig.String())
signatures.WriteString(" ")
}

fmt.Println(signatures)
return nil
},
}
}

// GetEvidenceQueryCmd creates a query sub-command for the claim module using cmdName as the name of the sub-command.
func GetEvidenceQueryCmd(storeName string, cdc *codec.Codec) *cobra.Command {
return &cobra.Command{
Use: "evidence <evidence-address> <signer-address>",
Short: "get evidence for claim",
Args: cobra.ExactArgs(2),
RunE: func(cmd *cobra.Command, args []string) error {
cliCtx := context.NewCLIContext().WithCodec(cdc)
content, err := types.DecodeBech32DataAddress(args[0])
if err != nil {
return err
}
signer, err := sdk.AccAddressFromBech32(args[1])
if err != nil {
return err
}

res, err := cliCtx.QueryStore(claim.KeySignatureEvidence(content, signer), storeName)
if err != nil {
return err
}

if len(res) == 0 {
return fmt.Errorf("no evidence for claim")
}

var evidence []types.DataAddress
err = cdc.UnmarshalBinaryBare(res, &evidence)
if err != nil {
return err
}

var evidenceString strings.Builder

for _, data := range evidence {
evidenceString.WriteString(data.String())
evidenceString.WriteString(" ")
}

fmt.Println(evidenceString)
return nil
},
}
}

62 changes: 62 additions & 0 deletions x/claim/client/cli/tx.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package cli

import (
"github.com/cosmos/cosmos-sdk/client/context"
"github.com/cosmos/cosmos-sdk/client/utils"
"github.com/cosmos/cosmos-sdk/codec"
sdk "github.com/cosmos/cosmos-sdk/types"
authtxb "github.com/cosmos/cosmos-sdk/x/auth/client/txbuilder"
"github.com/regen-network/regen-ledger/types"
"github.com/regen-network/regen-ledger/x/claim"
"github.com/spf13/cobra"
)

// GetCmdSignClaim returns the tx claim sign command.
func GetCmdSignClaim(cdc *codec.Codec) *cobra.Command {
var evidence []string
cmd := &cobra.Command{
Use: "sign <content-address> [--evidence <evidence-addresses>] --from <signer>",
Short: "sign a claim on the blockchain",
Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
cliCtx := context.NewCLIContext().WithCodec(cdc).WithAccountDecoder(cdc)

txBldr := authtxb.NewTxBuilderFromCLI().WithTxEncoder(utils.GetTxEncoder(cdc))

if err := cliCtx.EnsureAccountExists(); err != nil {
return err
}

account := cliCtx.GetFromAddress()

contentAddr, err := types.DecodeBech32DataAddress(args[0])
if err != nil {
return err
}

evidenceAddrs := make([]types.DataAddress, len(evidence))
for i, bech := range evidence {
evidenceAddrs[i], err = types.DecodeBech32DataAddress(bech)
if err != nil {
return err
}
}

msg := claim.MsgSignClaim{
Content: contentAddr,
Signers: []sdk.AccAddress{account},
Evidence: evidenceAddrs,
}
err = msg.ValidateBasic()
if err != nil {
return err
}

cliCtx.PrintResponse = true

return utils.CompleteAndBroadcastTxCLI(txBldr, cliCtx, []sdk.Msg{msg})
},
}
cmd.Flags().StringSliceVar(&evidence, "evidence", nil, "A comma-separated list of data addresses representing claim evidence")
return cmd
}
Loading

0 comments on commit da1c1f0

Please sign in to comment.