Skip to content

Commit

Permalink
🔀 #91 ✨ Make ISCN ID deterministic
Browse files Browse the repository at this point in the history
  • Loading branch information
williamchong authored Jan 5, 2023
2 parents 8b861aa + e4134e8 commit d0e6f86
Show file tree
Hide file tree
Showing 10 changed files with 312 additions and 54 deletions.
2 changes: 1 addition & 1 deletion dual_prefix_tests/iscn_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ func testCreateAndTransferISCNWithBech32(t *testing.T, from string, to string) {
Stakeholders: []iscntypes.IscnInput{stakeholder1, stakeholder2},
ContentMetadata: contentMetadata1,
}
msg := iscntypes.NewMsgCreateIscnRecord(fromAddr, &record)
msg := iscntypes.NewMsgCreateIscnRecord(fromAddr, &record, 0)
result := app.DeliverMsgNoError(t, msg, priv1)
events := result.GetEvents()

Expand Down
1 change: 1 addition & 0 deletions proto/likechain/iscn/tx.proto
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ message IscnRecord {
message MsgCreateIscnRecord {
string from = 1;
IscnRecord record = 2 [(gogoproto.nullable) = false];
uint64 nonce = 3;
}

message MsgCreateIscnRecordResponse {
Expand Down
30 changes: 15 additions & 15 deletions x/iscn/app_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ func TestBasicCreateAndUpdateAndChangeOwnership(t *testing.T) {
Stakeholders: []types.IscnInput{stakeholder1, stakeholder2},
ContentMetadata: contentMetadata1,
}
msg = types.NewMsgCreateIscnRecord(addr1, &record)
msg = types.NewMsgCreateIscnRecord(addr1, &record, 0)
result := app.DeliverMsgNoError(t, msg, priv1)

events := result.GetEvents()
Expand Down Expand Up @@ -327,8 +327,8 @@ func TestMultipleCreateInOneTx(t *testing.T) {
ContentMetadata: contentMetadata1,
}
msgs := []sdk.Msg{
types.NewMsgCreateIscnRecord(addr1, &record1),
types.NewMsgCreateIscnRecord(addr1, &record2),
types.NewMsgCreateIscnRecord(addr1, &record1, 0),
types.NewMsgCreateIscnRecord(addr1, &record2, 0),
}
app.DeliverMsgsNoError(t, msgs, priv1)
}
Expand All @@ -347,7 +347,7 @@ func TestOwnerQueryPagination(t *testing.T) {
ContentMetadata: contentMetadata1,
RecordNotes: fmt.Sprintf("update record 1 to version %010d", 1),
}
msg = types.NewMsgCreateIscnRecord(addr1, &record)
msg = types.NewMsgCreateIscnRecord(addr1, &record, 0)
result := app.DeliverMsgNoError(t, msg, priv1)
events := result.GetEvents()
iscnId1StrBytes := testutil.GetEventAttribute(events, "iscn_record", []byte("iscn_id"))
Expand All @@ -362,7 +362,7 @@ func TestOwnerQueryPagination(t *testing.T) {
}

record.RecordNotes = fmt.Sprintf("update record 2 to version %010d", 1)
msg = types.NewMsgCreateIscnRecord(addr1, &record)
msg = types.NewMsgCreateIscnRecord(addr1, &record, 0)
result = app.DeliverMsgNoError(t, msg, priv1)
events = result.GetEvents()
iscnId2StrBytes := testutil.GetEventAttribute(events, "iscn_record", []byte("iscn_id"))
Expand All @@ -374,7 +374,7 @@ func TestOwnerQueryPagination(t *testing.T) {
app.DeliverMsgNoError(t, msg, priv1)

record.RecordNotes = fmt.Sprintf("update record 3 to version %010d", 1)
msg = types.NewMsgCreateIscnRecord(addr1, &record)
msg = types.NewMsgCreateIscnRecord(addr1, &record, 0)
result = app.DeliverMsgNoError(t, msg, priv1)
events = result.GetEvents()
iscnId3StrBytes := testutil.GetEventAttribute(events, "iscn_record", []byte("iscn_id"))
Expand Down Expand Up @@ -436,7 +436,7 @@ func TestFingerprintQueryPagination(t *testing.T) {
}
for i := 0; i < 2*keeper.FingerprintRecordsPageLimit-1; i++ {
record.RecordNotes = fmt.Sprintf("record %010d", i)
msg = types.NewMsgCreateIscnRecord(addr1, &record)
msg = types.NewMsgCreateIscnRecord(addr1, &record, 0)
app.DeliverMsgNoError(t, msg, priv1)
}

Expand Down Expand Up @@ -489,22 +489,22 @@ func TestFailureCases(t *testing.T) {

// ensure everything works fine when no modification is made
record = goodRecord()
msg = types.NewMsgCreateIscnRecord(addr1, &record)
msg = types.NewMsgCreateIscnRecord(addr1, &record, 0)
res := app.DeliverMsgNoError(t, msg, priv1)
iscnId, err := types.ParseIscnId(string(testutil.GetEventAttribute(res.GetEvents(), "iscn_record", []byte("iscn_id"))))
require.NoError(t, err)

// wrong sender address checksum
record = goodRecord()
msg = &types.MsgCreateIscnRecord{"cosmos1ww3qews2y5jxe8apw2zt8stqqrcu2tptejfwag", record}
msg = &types.MsgCreateIscnRecord{"cosmos1ww3qews2y5jxe8apw2zt8stqqrcu2tptejfwag", record, 0}
_, err, simErr, _ := app.DeliverMsg(msg, priv1)
require.NoError(t, err)
require.Error(t, simErr)
require.True(t, errors.Is(simErr, sdkerrors.ErrInvalidAddress))

// wrong sender address prefix
record = goodRecord()
msg = &types.MsgCreateIscnRecord{"iaa1nr4zjtg87mtgvf2zetvmny8htuxplsduyc0h9f", record}
msg = &types.MsgCreateIscnRecord{"iaa1nr4zjtg87mtgvf2zetvmny8htuxplsduyc0h9f", record, 0}
_, err, simErr, _ = app.DeliverMsg(msg, priv1)
require.NoError(t, err)
require.Error(t, simErr)
Expand All @@ -513,7 +513,7 @@ func TestFailureCases(t *testing.T) {
// invalid fingerprint
record = goodRecord()
record.ContentFingerprints[0] = ""
msg = types.NewMsgCreateIscnRecord(addr1, &record)
msg = types.NewMsgCreateIscnRecord(addr1, &record, 0)
_, err, simErr, _ = app.DeliverMsg(msg, priv1)
require.NoError(t, err)
require.Error(t, simErr)
Expand All @@ -522,7 +522,7 @@ func TestFailureCases(t *testing.T) {
// invalid stakeholder
record = goodRecord()
record.Stakeholders[0] = types.IscnInput(``)
msg = types.NewMsgCreateIscnRecord(addr1, &record)
msg = types.NewMsgCreateIscnRecord(addr1, &record, 0)
_, err, simErr, _ = app.DeliverMsg(msg, priv1)
require.NoError(t, err)
require.Error(t, simErr)
Expand All @@ -531,15 +531,15 @@ func TestFailureCases(t *testing.T) {
// invalid content metadata
record = goodRecord()
record.ContentMetadata = types.IscnInput(``)
msg = types.NewMsgCreateIscnRecord(addr1, &record)
msg = types.NewMsgCreateIscnRecord(addr1, &record, 0)
_, err, simErr, _ = app.DeliverMsg(msg, priv1)
require.NoError(t, err)
require.Error(t, simErr)
require.True(t, errors.Is(simErr, types.ErrInvalidIscnRecord))

// balance not enough for ISCN fee
record = goodRecord()
msg = types.NewMsgCreateIscnRecord(addr2, &record)
msg = types.NewMsgCreateIscnRecord(addr2, &record, 0)
_, err, simErr, _ = app.DeliverMsg(msg, priv2)
require.NoError(t, err)
require.Error(t, simErr)
Expand Down Expand Up @@ -750,7 +750,7 @@ func TestSimulation(t *testing.T) {
record := goodRecord()
notes := fmt.Sprintf("create notes %d", r.Int63())
record.RecordNotes = notes
msg := types.NewMsgCreateIscnRecord(addr, &record)
msg := types.NewMsgCreateIscnRecord(addr, &record, 0)
res := app.DeliverMsgNoError(t, msg, privKey)
iscnId, err := types.ParseIscnId(string(testutil.GetEventAttribute(res.GetEvents(), "iscn_record", []byte("iscn_id"))))
require.NoError(t, err)
Expand Down
15 changes: 13 additions & 2 deletions x/iscn/client/cli/tx.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@ import (
"github.com/likecoin/likecoin-chain/v3/x/iscn/types"
)

const (
flagNonce = "nonce"
)

func NewTxCmd() *cobra.Command {
txCmd := &cobra.Command{
Use: types.ModuleName,
Expand Down Expand Up @@ -48,7 +52,7 @@ func readIscnRecordFile(path string) (*types.IscnRecord, error) {

func NewCreateIscnTxCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "create-iscn [iscn_record_json_file]",
Use: "create-iscn [iscn_record_json_file] (--nonce [nonce])",
Short: `Create an ISCN record from the given file. The ISCN record will be registered on chain and assigned an ISCN ID.`,
Long: strings.TrimSpace(
fmt.Sprintf(`Create an ISCN record on the chain. The record and the related parameters are given in the JSON file.
Expand Down Expand Up @@ -88,7 +92,13 @@ Where:
if err != nil {
return err
}
msg := types.NewMsgCreateIscnRecord(clientCtx.GetFromAddress(), record)

nonce, err := cmd.Flags().GetUint64(flagNonce)
if err != nil {
return err
}

msg := types.NewMsgCreateIscnRecord(clientCtx.GetFromAddress(), record, nonce)
err = msg.ValidateBasic()
if err != nil {
return err
Expand All @@ -97,6 +107,7 @@ Where:
},
}
flags.AddTxFlagsToCmd(cmd)
cmd.Flags().Uint64(flagNonce, 0, "Nonce of the ISCN registration transaction")
return cmd
}

Expand Down
2 changes: 1 addition & 1 deletion x/iscn/keeper/keeper.go
Original file line number Diff line number Diff line change
Expand Up @@ -284,7 +284,7 @@ func (k Keeper) AddIscnRecord(
}
}
if k.GetIscnIdSequence(ctx, iscnId) != 0 {
return nil, sdkerrors.Wrapf(types.ErrReusingIscnId, "%s", iscnId.String())
return nil, sdkerrors.Wrapf(types.ErrReusingIscnId, "%s, please set a different nonce in MsgCreateIscnRecord", iscnId.String())
}
cid := types.ComputeDataCid(data)
if k.GetCidSequence(ctx, cid) != 0 {
Expand Down
2 changes: 1 addition & 1 deletion x/iscn/keeper/msg_server.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ func (k msgServer) CreateIscnRecord(goCtx context.Context, msg *MsgCreateIscnRec
return nil, sdkerrors.Wrapf(sdkerrors.ErrInvalidAddress, "invalid sender address: %s", err.Error())
}
registryName := k.RegistryName(ctx)
seed := types.EncodeUint64(k.GetSequenceCount(ctx))
seed := msg.GetSignBytes()
id := types.GenerateNewIscnIdWithSeed(registryName, seed)
recordJsonLd, err := msg.Record.ToJsonLd(&types.IscnRecordJsonLdInfo{
Id: id,
Expand Down
1 change: 1 addition & 0 deletions x/iscn/types/iscnid.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ func (iscnId *IscnId) UnmarshalJSON(bz []byte) error {
func GenerateNewIscnIdWithSeed(registryName string, seed []byte) IscnId {
hasher := tmhash.New()
hasher.Write([]byte(registryName))
hasher.Write([]byte{'/'})
hasher.Write(seed)
contentIdBytes := hasher.Sum(nil)
contentId := base64.RawURLEncoding.EncodeToString(contentIdBytes)
Expand Down
Loading

0 comments on commit d0e6f86

Please sign in to comment.