diff --git a/go.mod b/go.mod index 8476dd2d9c3d316c3beaf0386e19cfe87a5bc7e0..f94bf1e03a7c60c48267a2a3f2025518a1cc2ca6 100644 --- a/go.mod +++ b/go.mod @@ -7,8 +7,8 @@ require ( github.com/hack-pad/go-indexeddb v0.2.0 github.com/pkg/errors v0.9.1 github.com/spf13/jwalterweatherman v1.1.0 - gitlab.com/elixxir/client v1.5.1-0.20220928170652-fe87f3ae67b4 - gitlab.com/elixxir/crypto v0.0.7-0.20220923233816-0364f1b203c6 + gitlab.com/elixxir/client v1.5.1-0.20221003205254-6cfac3468914 + gitlab.com/elixxir/crypto v0.0.7-0.20221003185354-b091598d2322 gitlab.com/elixxir/primitives v0.0.3-0.20220901220638-1acc75fabdc6 gitlab.com/xx_network/primitives v0.0.4-0.20220809193445-9fc0a5209548 ) diff --git a/go.sum b/go.sum index debddfda7ad3945a94413b9eea2b1c75c0369d54..568c82a5376fe142b41ecebb6cdae435cc61340f 100644 --- a/go.sum +++ b/go.sum @@ -636,6 +636,18 @@ gitlab.com/elixxir/client v1.5.1-0.20220925005456-24eb354b1d6f h1:m0jwFnBatQH/3u gitlab.com/elixxir/client v1.5.1-0.20220925005456-24eb354b1d6f/go.mod h1:z1Bdlja75CF3UrzifMC0LQwjlEdOcJCfXEX5k9AKQTQ= gitlab.com/elixxir/client v1.5.1-0.20220928170652-fe87f3ae67b4 h1:WgpR5CjPDXSRF5lpRhyyexmNsMQq9xiwMJd3HeDOb68= gitlab.com/elixxir/client v1.5.1-0.20220928170652-fe87f3ae67b4/go.mod h1:z1Bdlja75CF3UrzifMC0LQwjlEdOcJCfXEX5k9AKQTQ= +gitlab.com/elixxir/client v1.5.1-0.20221003171000-d0367733252c h1:3Vegb3loIg9UGj6tG4je5jUSmum6I1vv5848InsJk9w= +gitlab.com/elixxir/client v1.5.1-0.20221003171000-d0367733252c/go.mod h1:z1Bdlja75CF3UrzifMC0LQwjlEdOcJCfXEX5k9AKQTQ= +gitlab.com/elixxir/client v1.5.1-0.20221003181318-ad80fa9efc50 h1:4BMaEwzDZIkDEqMJTqnhoZGTUbLIxldSa7JgDOXBVk4= +gitlab.com/elixxir/client v1.5.1-0.20221003181318-ad80fa9efc50/go.mod h1:z1Bdlja75CF3UrzifMC0LQwjlEdOcJCfXEX5k9AKQTQ= +gitlab.com/elixxir/client v1.5.1-0.20221003182734-3e6c09af242a h1:c3oTU3DtOhDG2DU1jNyUMziNOWVsRzpoSqrLdOUrezo= +gitlab.com/elixxir/client v1.5.1-0.20221003182734-3e6c09af242a/go.mod h1:z1Bdlja75CF3UrzifMC0LQwjlEdOcJCfXEX5k9AKQTQ= +gitlab.com/elixxir/client v1.5.1-0.20221003194042-5539ac20b937 h1:a0AM2V07rtUhTyZGfBNIXQtihMM3ZmcRktcgb5WTsxE= +gitlab.com/elixxir/client v1.5.1-0.20221003194042-5539ac20b937/go.mod h1:wuTIcLuMnvIGSo8i/Gg/SbYF57bE+CbKPpA1Xbk2AKk= +gitlab.com/elixxir/client v1.5.1-0.20221003200717-5f4afe50a1fe h1:q5TtT4szh+0+1iM+CRm3IYkWuP09VB5QQ6l/2/PDkcY= +gitlab.com/elixxir/client v1.5.1-0.20221003200717-5f4afe50a1fe/go.mod h1:wuTIcLuMnvIGSo8i/Gg/SbYF57bE+CbKPpA1Xbk2AKk= +gitlab.com/elixxir/client v1.5.1-0.20221003205254-6cfac3468914 h1:ZWf+WxkfoRh41hoeVPZ7L5AI1puJw324bXT9QI4Er4I= +gitlab.com/elixxir/client v1.5.1-0.20221003205254-6cfac3468914/go.mod h1:wuTIcLuMnvIGSo8i/Gg/SbYF57bE+CbKPpA1Xbk2AKk= gitlab.com/elixxir/comms v0.0.4-0.20220916185715-f1e9a5eda939 h1:+VRx2ULHKs040bBhDAOKNCZnbcXxUk3jD9JoKQzQpLk= gitlab.com/elixxir/comms v0.0.4-0.20220916185715-f1e9a5eda939/go.mod h1:AO6XkMhaHJW8eXlgL5m3UUcJqsSP8F5Wm1GX+wyq/rw= gitlab.com/elixxir/crypto v0.0.0-20200804182833-984246dea2c4/go.mod h1:ucm9SFKJo+K0N2GwRRpaNr+tKXMIOVWzmyUD0SbOu2c= @@ -643,6 +655,8 @@ gitlab.com/elixxir/crypto v0.0.3/go.mod h1:ZNgBOblhYToR4m8tj4cMvJ9UsJAUKq+p0gCp0 gitlab.com/elixxir/crypto v0.0.7-0.20220913220142-ab0771bad0af/go.mod h1:QF8SzsrYh9Elip9EUYUDAhPjqO9DGrrrQxYHvn+VXok= gitlab.com/elixxir/crypto v0.0.7-0.20220923233816-0364f1b203c6 h1:ZCMqzKB86nrs9ldIoF2ZHvcExrkXIIIeH2RlNVwZx2A= gitlab.com/elixxir/crypto v0.0.7-0.20220923233816-0364f1b203c6/go.mod h1:QF8SzsrYh9Elip9EUYUDAhPjqO9DGrrrQxYHvn+VXok= +gitlab.com/elixxir/crypto v0.0.7-0.20221003185354-b091598d2322 h1:8unQE70BDNRXTWUbjOO9d4kWyh19LySlTZo0Jqx0gPE= +gitlab.com/elixxir/crypto v0.0.7-0.20221003185354-b091598d2322/go.mod h1:QF8SzsrYh9Elip9EUYUDAhPjqO9DGrrrQxYHvn+VXok= gitlab.com/elixxir/ekv v0.2.1 h1:dtwbt6KmAXG2Tik5d60iDz2fLhoFBgWwST03p7T+9Is= gitlab.com/elixxir/ekv v0.2.1/go.mod h1:USLD7xeDnuZEavygdrgzNEwZXeLQJK/w1a+htpN+JEU= gitlab.com/elixxir/primitives v0.0.0-20200731184040-494269b53b4d/go.mod h1:OQgUZq7SjnE0b+8+iIAT2eqQF+2IFHn73tOo+aV11mg= diff --git a/indexedDb/implementation.go b/indexedDb/implementation.go index d8053bc9119bcadd21dac1a743b0af2ff47e3acf..1d8d804074140da708672192358375f6a3ebe4dd 100644 --- a/indexedDb/implementation.go +++ b/indexedDb/implementation.go @@ -149,34 +149,31 @@ func (w *wasmModel) LeaveChannel(channelID *id.ID) { // It may be called multiple times on the same message; it is incumbent on the // user of the API to filter such called by message ID. func (w *wasmModel) ReceiveMessage(channelID *id.ID, - messageID cryptoChannel.MessageID, - nickname, text string, identity cryptoChannel.Identity, - timestamp time.Time, lease time.Duration, round rounds.Round, + messageID cryptoChannel.MessageID, nickname, text string, + identity cryptoChannel.Identity, timestamp time.Time, lease time.Duration, + round rounds.Round, mType channels.MessageType, status channels.SentStatus) uint64 { - parentErr := errors.New("failed to ReceiveMessage") - msgToInsert := buildMessage(channelID.Marshal(), - messageID.Bytes(), nil, nickname, text, identity, - timestamp, lease, status) + msgToInsert := buildMessage(channelID.Marshal(), messageID.Bytes(), nil, + nickname, text, identity, timestamp, lease, round.ID, mType, status) - // Attempt a lookup on the MessageID if it is non-zero to find - // an existing entry for it. This occurs any time a sender - // receives their own message from the mixnet. + // Attempt a lookup on the MessageID if it is non-zero to find an existing + // entry for it. This occurs any time a sender receives their own message + // from the mixnet. if !messageID.Equals(cryptoChannel.MessageID{}) { uuid, err := w.msgIDLookup(messageID) if err != nil { - // NOTE: No stack is OK here - jww.WARN.Printf(err.Error()) + // message is already in the database, no insert necessary + return uuid } - msgToInsert.ID = uuid } uuid, err := w.receiveHelper(msgToInsert) if err != nil { - jww.ERROR.Printf("%+v", errors.Wrap(parentErr, err.Error())) + jww.ERROR.Printf("Failed to receiver message: %+v", err) } - go w.receivedMessageCB(uuid, channelID) + go w.receivedMessageCB(uuid, channelID, false) return uuid } @@ -187,19 +184,32 @@ func (w *wasmModel) ReceiveMessage(channelID *id.ID, // Messages may arrive our of order, so a reply, in theory, can arrive before // the initial message. As a result, it may be important to buffer replies. func (w *wasmModel) ReceiveReply(channelID *id.ID, - messageID cryptoChannel.MessageID, - replyTo cryptoChannel.MessageID, nickname, text string, - identity cryptoChannel.Identity, timestamp time.Time, - lease time.Duration, round rounds.Round, status channels.SentStatus) uint64 { - parentErr := errors.New("failed to ReceiveReply") + messageID cryptoChannel.MessageID, replyTo cryptoChannel.MessageID, + nickname, text string, identity cryptoChannel.Identity, timestamp time.Time, + lease time.Duration, round rounds.Round, mType channels.MessageType, + status channels.SentStatus) uint64 { + + msgToInsert := buildMessage(channelID.Marshal(), messageID.Bytes(), + replyTo.Bytes(), nickname, text, identity, timestamp, lease, round.ID, + mType, status) + + // Attempt a lookup on the MessageID if it is non-zero to find an existing + // entry for it. This occurs any time a sender receives their own message + // from the mixnet. + if !messageID.Equals(cryptoChannel.MessageID{}) { + uuid, err := w.msgIDLookup(messageID) + if err != nil { + // message is already in the database, no insert necessary + return uuid + } + } + + uuid, err := w.receiveHelper(msgToInsert) - uuid, err := w.receiveHelper(buildMessage(channelID.Marshal(), - messageID.Bytes(), replyTo.Bytes(), nickname, text, identity, - timestamp, lease, status)) if err != nil { - jww.ERROR.Printf("%+v", errors.Wrap(parentErr, err.Error())) + jww.ERROR.Printf("Failed to receive reply: %+v", err) } - go w.receivedMessageCB(uuid, channelID) + go w.receivedMessageCB(uuid, channelID, false) return uuid } @@ -209,25 +219,39 @@ func (w *wasmModel) ReceiveReply(channelID *id.ID, // // Messages may arrive our of order, so a reply, in theory, can arrive before // the initial message. As a result, it may be important to buffer reactions. -func (w *wasmModel) ReceiveReaction(channelID *id.ID, messageID cryptoChannel.MessageID, - reactionTo cryptoChannel.MessageID, nickname, reaction string, - identity cryptoChannel.Identity, timestamp time.Time, - lease time.Duration, round rounds.Round, status channels.SentStatus) uint64 { - parentErr := errors.New("failed to ReceiveReaction") +func (w *wasmModel) ReceiveReaction(channelID *id.ID, + messageID cryptoChannel.MessageID, reactionTo cryptoChannel.MessageID, + nickname, reaction string, identity cryptoChannel.Identity, + timestamp time.Time, lease time.Duration, round rounds.Round, + mType channels.MessageType, status channels.SentStatus) uint64 { + + msgToInsert := buildMessage(channelID.Marshal(), messageID.Bytes(), + reactionTo.Bytes(), nickname, reaction, identity, timestamp, lease, + round.ID, mType, status) - uuid, err := w.receiveHelper(buildMessage(channelID.Marshal(), - messageID.Bytes(), reactionTo.Bytes(), nickname, reaction, - identity, timestamp, lease, status)) + // Attempt a lookup on the MessageID if it is non-zero to find + // an existing entry for it. This occurs any time a sender + // receives their own message from the mixnet. + if !messageID.Equals(cryptoChannel.MessageID{}) { + uuid, err := w.msgIDLookup(messageID) + if err != nil { + // message is already in the database, no insert necessary + return uuid + } + } + + uuid, err := w.receiveHelper(msgToInsert) if err != nil { - jww.ERROR.Printf("%+v", errors.Wrap(parentErr, err.Error())) + jww.ERROR.Printf("Failed to receive reaction: %+v", err) } - go w.receivedMessageCB(uuid, channelID) + go w.receivedMessageCB(uuid, channelID, false) return uuid } -// UpdateSentStatus is called whenever the [channels.SentStatus] of a -// message has changed. At this point the message ID goes from -// empty/unknown to populated. +// UpdateSentStatus is called whenever the [channels.SentStatus] of a message +// has changed. At this point the message ID goes from empty/unknown to +// populated. +// // TODO: Potential race condition due to separate get/update operations. func (w *wasmModel) UpdateSentStatus(uuid uint64, messageID cryptoChannel.MessageID, timestamp time.Time, round rounds.Round, status channels.SentStatus) { @@ -255,7 +279,17 @@ func (w *wasmModel) UpdateSentStatus(uuid uint64, messageID cryptoChannel.Messag return } newMessage.Status = uint8(status) - newMessage.MessageID = messageID.Bytes() + if !messageID.Equals(cryptoChannel.MessageID{}) { + newMessage.MessageID = messageID.Bytes() + } + + if round.ID == 0 { + newMessage.Round = uint64(round.ID) + } + + if !timestamp.Equal(time.Time{}) { + newMessage.Timestamp = timestamp + } // Store the updated Message _, err = w.receiveHelper(newMessage) @@ -264,7 +298,7 @@ func (w *wasmModel) UpdateSentStatus(uuid uint64, messageID cryptoChannel.Messag } channelID := &id.ID{} copy(channelID[:], newMessage.ChannelID) - go w.receivedMessageCB(uuid, channelID) + go w.receivedMessageCB(uuid, channelID, true) } // buildMessage is a private helper that converts typical [channels.EventModel] @@ -273,9 +307,9 @@ func (w *wasmModel) UpdateSentStatus(uuid uint64, messageID cryptoChannel.Messag // autoincrement key by default. If you are trying to overwrite // an existing message, then you need to set it manually // yourself. -func buildMessage(channelID, messageID, parentID []byte, nickname, - text string, identity cryptoChannel.Identity, timestamp time.Time, - lease time.Duration, +func buildMessage(channelID, messageID, parentID []byte, nickname, text string, + identity cryptoChannel.Identity, timestamp time.Time, lease time.Duration, + round id.Round, mType channels.MessageType, status channels.SentStatus) *Message { return &Message{ MessageID: messageID, @@ -288,8 +322,10 @@ func buildMessage(channelID, messageID, parentID []byte, nickname, Hidden: false, Pinned: false, Text: text, + Type: uint16(mType), + Round: uint64(round), // User Identity Info - Pubkey: []byte(identity.PubKey), + Pubkey: identity.PubKey, Codename: identity.Codename, Color: identity.Color, Extension: identity.Extension, diff --git a/indexedDb/implementation_test.go b/indexedDb/implementation_test.go index 9b728f28d1fe0d400c0c1aa0ef9d93b2e71b2aea..f47117f7171ce9851b05a5017745c3b4651370c8 100644 --- a/indexedDb/implementation_test.go +++ b/indexedDb/implementation_test.go @@ -29,12 +29,12 @@ func TestMain(m *testing.M) { os.Exit(m.Run()) } -func dummyCallback(uuid uint64, channelID *id.ID) {} +func dummyCallback(uint64, *id.ID, bool) {} // Test wasmModel.UpdateSentStatus happy path and ensure fields don't change. func TestWasmModel_UpdateSentStatus(t *testing.T) { testString := "test" - testMsgId := channel.MakeMessageID([]byte(testString)) + testMsgId := channel.MakeMessageID([]byte(testString), &id.ID{1}) eventModel, err := newWASMModel(testString, dummyCallback) if err != nil { t.Fatalf("%+v", err) @@ -43,9 +43,9 @@ func TestWasmModel_UpdateSentStatus(t *testing.T) { cid := channel.Identity{} // Store a test message - testMsg := buildMessage([]byte(testString), testMsgId.Bytes(), - nil, testString, testString, cid, time.Now(), - time.Second, channels.Sent) + testMsg := buildMessage([]byte(testString), testMsgId.Bytes(), nil, + testString, testString, cid, time.Now(), time.Second, 0, 0, + channels.Sent) uuid, err := eventModel.receiveHelper(testMsg) if err != nil { t.Fatalf("%+v", err) @@ -148,15 +148,15 @@ func TestWasmModel_UUIDTest(t *testing.T) { // Store a test message channelID := id.NewIdFromBytes([]byte(testString), t) msgID := channel.MessageID{} - copy(msgID[:], []byte(testString+fmt.Sprintf("%d", i))) + copy(msgID[:], testString+fmt.Sprintf("%d", i)) rnd := rounds.Round{ID: id.Round(42)} uuid := eventModel.ReceiveMessage(channelID, msgID, "test", testString+fmt.Sprintf("%d", i), cid, time.Now(), - time.Hour, rnd, channels.Sent) + time.Hour, rnd, 0, channels.Sent) uuids[i] = uuid } - eventModel.dump(messageStoreName) + _, _ = eventModel.dump(messageStoreName) for i := 0; i < 10; i++ { for j := i + 1; j < 10; j++ { diff --git a/indexedDb/init.go b/indexedDb/init.go index af98dec26c3d2080da79276575c64c6f27286413..9f107ba0cb695e42b41f8d133f261a0703c58ce9 100644 --- a/indexedDb/init.go +++ b/indexedDb/init.go @@ -31,7 +31,8 @@ const ( ) // MessageReceivedCallback is called any time a message is received or updated -type MessageReceivedCallback func(uuid uint64, channelID *id.ID) +// update is true if the row is old and was edited +type MessageReceivedCallback func(uuid uint64, channelID *id.ID, update bool) // NewWASMEventModelBuilder returns an EventModelBuilder which allows // the channel manager to define the path but the callback is the same diff --git a/indexedDb/model.go b/indexedDb/model.go index 8d131954f0ae06956f3f766a1aad24c156ebd8cb..7204468bfc14b71ce5b7af6caf9a22329592735c 100644 --- a/indexedDb/model.go +++ b/indexedDb/model.go @@ -58,8 +58,10 @@ type Message struct { Hidden bool `json:"hidden"` Pinned bool `json:"pinned"` // Index Text string `json:"text"` + Type uint16 `json:"type"` + Round uint64 `json:"round"` - // User cryptographic IDentity struct -- could be pulled out + // User cryptographic Identity struct -- could be pulled out Pubkey []byte `json:"pubkey"` // Index // Honorific string `json:"honorific"` // Adjective string `json:"adjective"` diff --git a/wasm/channels.go b/wasm/channels.go index 31b0b4712318aa6a77635f43f3d14453347b301a..b8e58b14c22c2195fe2875edd26aa835ad498791 100644 --- a/wasm/channels.go +++ b/wasm/channels.go @@ -235,7 +235,8 @@ func LoadChannelsManager(_ js.Value, args []js.Value) interface{} { // returned as an int and the channelID as a Uint8Array. The row in the // database that was updated can be found using the UUID. The channel ID is // provided so that the recipient can filter if they want to the processes -// the update now or not. +// the update now or not. An "update" bool is present which tells you if +// the row is new or if it is an edited old row // // Returns a promise: // - Resolves to a Javascript representation of the [ChannelsManager] object. @@ -244,8 +245,8 @@ func NewChannelsManagerWithIndexedDb(_ js.Value, args []js.Value) interface{} { cmixID := args[0].Int() privateIdentity := utils.CopyBytesToGo(args[1]) - fn := func(uuid uint64, channelID *id.ID) { - args[2].Invoke(uuid, utils.CopyBytesToJS(channelID.Marshal())) + fn := func(uuid uint64, channelID *id.ID, update bool) { + args[2].Invoke(uuid, utils.CopyBytesToJS(channelID.Marshal()), update) } model := indexedDb.NewWASMEventModelBuilder(fn) @@ -281,7 +282,8 @@ func NewChannelsManagerWithIndexedDb(_ js.Value, args []js.Value) interface{} { // returned as an int and the channelID as a Uint8Array. The row in the // database that was updated can be found using the UUID. The channel ID is // provided so that the recipient can filter if they want to the processes -// the update now or not. +// the update now or not. An "update" bool is present which tells you if +// the row is new or if it is an edited old row // // Returns a promise: // - Resolves to a Javascript representation of the [ChannelsManager] object. @@ -290,8 +292,8 @@ func LoadChannelsManagerWithIndexedDb(_ js.Value, args []js.Value) interface{} { cmixID := args[0].Int() storageTag := args[1].String() - fn := func(uuid uint64, channelID *id.ID) { - args[2].Invoke(uuid, utils.CopyBytesToJS(channelID.Marshal())) + fn := func(uuid uint64, channelID *id.ID, updated bool) { + args[2].Invoke(uuid, utils.CopyBytesToJS(channelID.Marshal()), updated) } model := indexedDb.NewWASMEventModelBuilder(fn) @@ -872,6 +874,7 @@ func (em *eventModel) LeaveChannel(channelID []byte) { // since unix epoch (int). // - lease - The number of nanoseconds that the message is valid for (int). // - roundId - The ID of the round that the message was received on (int). +// - msgType - The type of message ([channels.MessageType]) to send (int). // - status - The [channels.SentStatus] of the message (int). // // Statuses will be enumerated as such: @@ -883,10 +886,12 @@ func (em *eventModel) LeaveChannel(channelID []byte) { // - A non-negative unique UUID for the message that it can be referenced by // later with [eventModel.UpdateSentStatus]. func (em *eventModel) ReceiveMessage(channelID, messageID []byte, nickname, - text string, identity []byte, timestamp, lease, roundId, status int64) int64 { + text string, identity []byte, timestamp, lease, roundId, msgType, + status int64) int64 { uuid := em.receiveMessage(utils.CopyBytesToJS(channelID), utils.CopyBytesToJS(messageID), nickname, text, - utils.CopyBytesToJS(identity), timestamp, lease, roundId, status) + utils.CopyBytesToJS(identity), + timestamp, lease, roundId, msgType, status) return int64(uuid.Int()) } @@ -911,6 +916,7 @@ func (em *eventModel) ReceiveMessage(channelID, messageID []byte, nickname, // since unix epoch (int). // - lease - The number of nanoseconds that the message is valid for (int). // - roundId - The ID of the round that the message was received on (int). +// - msgType - The type of message ([channels.MessageType]) to send (int). // - status - The [channels.SentStatus] of the message (int). // // Statuses will be enumerated as such: @@ -923,11 +929,11 @@ func (em *eventModel) ReceiveMessage(channelID, messageID []byte, nickname, // later with [eventModel.UpdateSentStatus]. func (em *eventModel) ReceiveReply(channelID, messageID, reactionTo []byte, senderUsername, text string, identity []byte, timestamp, lease, roundId, - status int64) int64 { + msgType, status int64) int64 { uuid := em.receiveReply(utils.CopyBytesToJS(channelID), utils.CopyBytesToJS(messageID), utils.CopyBytesToJS(reactionTo), senderUsername, text, utils.CopyBytesToJS(identity), - timestamp, lease, roundId, status) + timestamp, lease, roundId, msgType, status) return int64(uuid.Int()) } @@ -952,6 +958,7 @@ func (em *eventModel) ReceiveReply(channelID, messageID, reactionTo []byte, // since unix epoch (int). // - lease - The number of nanoseconds that the message is valid for (int). // - roundId - The ID of the round that the message was received on (int). +// - msgType - The type of message ([channels.MessageType]) to send (int). // - status - The [channels.SentStatus] of the message (int). // // Statuses will be enumerated as such: @@ -964,11 +971,11 @@ func (em *eventModel) ReceiveReply(channelID, messageID, reactionTo []byte, // later with [eventModel.UpdateSentStatus]. func (em *eventModel) ReceiveReaction(channelID, messageID, reactionTo []byte, senderUsername, reaction string, identity []byte, timestamp, lease, roundId, - status int64) int64 { + msgType, status int64) int64 { uuid := em.receiveReaction(utils.CopyBytesToJS(channelID), utils.CopyBytesToJS(messageID), utils.CopyBytesToJS(reactionTo), senderUsername, reaction, utils.CopyBytesToJS(identity), - timestamp, lease, roundId, status) + timestamp, lease, roundId, msgType, status) return int64(uuid.Int()) }