github.com/deso-protocol/core@v1.2.9/lib/block_view_message.go (about)

     1  package lib
     2  
     3  import (
     4  	"encoding/hex"
     5  	"fmt"
     6  	"github.com/btcsuite/btcd/btcec"
     7  	"github.com/golang/glog"
     8  	"github.com/pkg/errors"
     9  	"reflect"
    10  )
    11  
    12  func (bav *UtxoView) _getMessageEntryForMessageKey(messageKey *MessageKey) *MessageEntry {
    13  	// If an entry exists in the in-memory map, return the value of that mapping.
    14  	mapValue, existsMapValue := bav.MessageKeyToMessageEntry[*messageKey]
    15  	if existsMapValue {
    16  		return mapValue
    17  	}
    18  
    19  	// If we get here it means no value exists in our in-memory map. In this case,
    20  	// defer to the db. If a mapping exists in the db, return it. If not, return
    21  	// nil. Either way, save the value to the in-memory view mapping got later.
    22  	dbMessageEntry := DbGetMessageEntry(bav.Handle, messageKey.PublicKey[:], messageKey.TstampNanos)
    23  	if dbMessageEntry != nil {
    24  		bav._setMessageEntryMappings(dbMessageEntry)
    25  	}
    26  	return dbMessageEntry
    27  }
    28  
    29  func (bav *UtxoView) _setMessageEntryMappings(messageEntry *MessageEntry) {
    30  	// This function shouldn't be called with nil.
    31  	if messageEntry == nil {
    32  		glog.Errorf("_setMessageEntryMappings: Called with nil MessageEntry; " +
    33  			"this should never happen.")
    34  		return
    35  	}
    36  
    37  	// Add a mapping for the sender and the recipient.
    38  	senderKey := MakeMessageKey(messageEntry.SenderPublicKey, messageEntry.TstampNanos)
    39  	bav.MessageKeyToMessageEntry[senderKey] = messageEntry
    40  
    41  	recipientKey := MakeMessageKey(messageEntry.RecipientPublicKey, messageEntry.TstampNanos)
    42  	bav.MessageKeyToMessageEntry[recipientKey] = messageEntry
    43  }
    44  
    45  func (bav *UtxoView) _deleteMessageEntryMappings(messageEntry *MessageEntry) {
    46  
    47  	// Create a tombstone entry.
    48  	tombstoneMessageEntry := *messageEntry
    49  	tombstoneMessageEntry.isDeleted = true
    50  
    51  	// Set the mappings to point to the tombstone entry.
    52  	bav._setMessageEntryMappings(&tombstoneMessageEntry)
    53  }
    54  
    55  //
    56  // Postgres messages
    57  //
    58  
    59  func (bav *UtxoView) getMessage(messageHash *BlockHash) *PGMessage {
    60  	mapValue, existsMapValue := bav.MessageMap[*messageHash]
    61  	if existsMapValue {
    62  		return mapValue
    63  	}
    64  
    65  	message := bav.Postgres.GetMessage(messageHash)
    66  	if message != nil {
    67  		bav.setMessageMappings(message)
    68  	}
    69  	return message
    70  }
    71  
    72  func (bav *UtxoView) setMessageMappings(message *PGMessage) {
    73  	bav.MessageMap[*message.MessageHash] = message
    74  }
    75  
    76  func (bav *UtxoView) deleteMessageMappings(message *PGMessage) {
    77  	deletedMessage := *message
    78  	deletedMessage.isDeleted = true
    79  	bav.setMessageMappings(&deletedMessage)
    80  }
    81  
    82  // TODO: Update for Postgres
    83  func (bav *UtxoView) GetMessagesForUser(publicKey []byte) (
    84  	_messageEntries []*MessageEntry, _err error) {
    85  
    86  	// Start by fetching all the messages we have in the db.
    87  	dbMessageEntries, err := DbGetMessageEntriesForPublicKey(bav.Handle, publicKey)
    88  	if err != nil {
    89  		return nil, errors.Wrapf(err, "GetMessagesForUser: Problem fetching MessageEntrys from db: ")
    90  	}
    91  
    92  	// Iterate through the entries found in the db and force the view to load them.
    93  	// This fills in any gaps in the view so that, after this, the view should contain
    94  	// the union of what it had before plus what was in the db.
    95  	for _, dbMessageEntry := range dbMessageEntries {
    96  		messageKey := MakeMessageKey(publicKey, dbMessageEntry.TstampNanos)
    97  		bav._getMessageEntryForMessageKey(&messageKey)
    98  	}
    99  
   100  	// Now that the view mappings are a complete picture, iterate through them
   101  	// and set them on the map we're returning. Skip entries that don't match
   102  	// our public key or that are deleted. Note that only considering mappings
   103  	// where our public key is part of the key should ensure there are no
   104  	// duplicates in the resulting list.
   105  	messageEntriesToReturn := []*MessageEntry{}
   106  	for viewMessageKey, viewMessageEntry := range bav.MessageKeyToMessageEntry {
   107  		if viewMessageEntry.isDeleted {
   108  			continue
   109  		}
   110  		messageKey := MakeMessageKey(publicKey, viewMessageEntry.TstampNanos)
   111  		if viewMessageKey != messageKey {
   112  			continue
   113  		}
   114  
   115  		// At this point we are confident the map key is equal to the message
   116  		// key containing the passed-in public key so add it to the mapping.
   117  		messageEntriesToReturn = append(messageEntriesToReturn, viewMessageEntry)
   118  	}
   119  
   120  	return messageEntriesToReturn, nil
   121  }
   122  
   123  // TODO: Update for Postgres
   124  func (bav *UtxoView) GetLimitedMessagesForUser(publicKey []byte) (
   125  	_messageEntries []*MessageEntry, _err error) {
   126  
   127  	// Start by fetching all the messages we have in the db.
   128  	dbMessageEntries, err := DbGetLimitedMessageEntriesForPublicKey(bav.Handle, publicKey)
   129  	if err != nil {
   130  		return nil, errors.Wrapf(err, "GetMessagesForUser: Problem fetching MessageEntrys from db: ")
   131  	}
   132  
   133  	// Iterate through the entries found in the db and force the view to load them.
   134  	// This fills in any gaps in the view so that, after this, the view should contain
   135  	// the union of what it had before plus what was in the db.
   136  	for _, dbMessageEntry := range dbMessageEntries {
   137  		messageKey := MakeMessageKey(publicKey, dbMessageEntry.TstampNanos)
   138  		bav._getMessageEntryForMessageKey(&messageKey)
   139  	}
   140  
   141  	// Now that the view mappings are a complete picture, iterate through them
   142  	// and set them on the map we're returning. Skip entries that don't match
   143  	// our public key or that are deleted. Note that only considering mappings
   144  	// where our public key is part of the key should ensure there are no
   145  	// duplicates in the resulting list.
   146  	messageEntriesToReturn := []*MessageEntry{}
   147  	for viewMessageKey, viewMessageEntry := range bav.MessageKeyToMessageEntry {
   148  		if viewMessageEntry.isDeleted {
   149  			continue
   150  		}
   151  		messageKey := MakeMessageKey(publicKey, viewMessageEntry.TstampNanos)
   152  		if viewMessageKey != messageKey {
   153  			continue
   154  		}
   155  
   156  		// At this point we are confident the map key is equal to the message
   157  		// key containing the passed-in public key so add it to the mapping.
   158  		messageEntriesToReturn = append(messageEntriesToReturn, viewMessageEntry)
   159  	}
   160  
   161  	return messageEntriesToReturn, nil
   162  }
   163  
   164  func (bav *UtxoView) _connectPrivateMessage(
   165  	txn *MsgDeSoTxn, txHash *BlockHash, blockHeight uint32, verifySignatures bool) (
   166  	_totalInput uint64, _totalOutput uint64, _utxoOps []*UtxoOperation, _err error) {
   167  
   168  	// Check that the transaction has the right TxnType.
   169  	if txn.TxnMeta.GetTxnType() != TxnTypePrivateMessage {
   170  		return 0, 0, nil, fmt.Errorf("_connectPrivateMessage: called with bad TxnType %s",
   171  			txn.TxnMeta.GetTxnType().String())
   172  	}
   173  	txMeta := txn.TxnMeta.(*PrivateMessageMetadata)
   174  
   175  	// Check the length of the EncryptedText
   176  	if uint64(len(txMeta.EncryptedText)) > bav.Params.MaxPrivateMessageLengthBytes {
   177  		return 0, 0, nil, errors.Wrapf(
   178  			RuleErrorPrivateMessageEncryptedTextLengthExceedsMax, "_connectPrivateMessage: "+
   179  				"EncryptedTextLen = %d; Max length = %d",
   180  			len(txMeta.EncryptedText), bav.Params.MaxPrivateMessageLengthBytes)
   181  	}
   182  
   183  	// Check that a proper public key is provided in the message metadata
   184  	if len(txMeta.RecipientPublicKey) != btcec.PubKeyBytesLenCompressed {
   185  		return 0, 0, nil, errors.Wrapf(
   186  			RuleErrorPrivateMessageRecipientPubKeyLen, "_connectPrivateMessage: "+
   187  				"RecipientPubKeyLen = %d; Expected length = %d",
   188  			len(txMeta.RecipientPublicKey), btcec.PubKeyBytesLenCompressed)
   189  	}
   190  	_, err := btcec.ParsePubKey(txMeta.RecipientPublicKey, btcec.S256())
   191  	if err != nil {
   192  		return 0, 0, nil, errors.Wrapf(
   193  			RuleErrorPrivateMessageParsePubKeyError, "_connectPrivateMessage: Parse error: %v", err)
   194  	}
   195  
   196  	// You can't send a message to yourself.
   197  	if reflect.DeepEqual(txn.PublicKey, txMeta.RecipientPublicKey) {
   198  		return 0, 0, nil, errors.Wrapf(
   199  			RuleErrorPrivateMessageSenderPublicKeyEqualsRecipientPublicKey,
   200  			"_connectPrivateMessage: Parse error: %v", err)
   201  	}
   202  
   203  	// Check that the timestamp is greater than zero. Not doing this could make
   204  	// the message not get returned when we call Seek() in our db. It's also just
   205  	// a reasonable sanity check.
   206  	if txMeta.TimestampNanos == 0 {
   207  		return 0, 0, nil, RuleErrorPrivateMessageTstampIsZero
   208  	}
   209  
   210  	// Connect basic txn to get the total input and the total output without
   211  	// considering the transaction metadata.
   212  	totalInput, totalOutput, utxoOpsForTxn, err := bav._connectBasicTransfer(
   213  		txn, txHash, blockHeight, verifySignatures)
   214  	if err != nil {
   215  		return 0, 0, nil, errors.Wrapf(err, "_connectPrivateMessage: ")
   216  	}
   217  
   218  	// At this point the inputs and outputs have been processed. Now we
   219  	// need to handle the metadata.
   220  
   221  	// If a message already exists and does not have isDeleted=true then return
   222  	// an error. In general, messages must have unique (pubkey, tstamp) tuples.
   223  	//
   224  	// Postgres does not enforce these rule errors
   225  	if bav.Postgres == nil {
   226  		senderMessageKey := MakeMessageKey(txn.PublicKey, txMeta.TimestampNanos)
   227  		senderMessage := bav._getMessageEntryForMessageKey(&senderMessageKey)
   228  		if senderMessage != nil && !senderMessage.isDeleted {
   229  			return 0, 0, nil, errors.Wrapf(
   230  				RuleErrorPrivateMessageExistsWithSenderPublicKeyTstampTuple,
   231  				"_connectPrivateMessage: Message key: %v", &senderMessageKey)
   232  		}
   233  		recipientMessageKey := MakeMessageKey(txMeta.RecipientPublicKey, txMeta.TimestampNanos)
   234  		recipientMessage := bav._getMessageEntryForMessageKey(&recipientMessageKey)
   235  		if recipientMessage != nil && !recipientMessage.isDeleted {
   236  			return 0, 0, nil, errors.Wrapf(
   237  				RuleErrorPrivateMessageExistsWithRecipientPublicKeyTstampTuple,
   238  				"_connectPrivateMessage: Message key: %v", &recipientMessageKey)
   239  		}
   240  	}
   241  
   242  	if verifySignatures {
   243  		// _connectBasicTransfer has already checked that the transaction is
   244  		// signed by the top-level public key, which we take to be the sender's
   245  		// public key so there is no need to verify anything further.
   246  	}
   247  
   248  	// At this point we are confident that we are parsing a message with a unique
   249  	// <PublicKey, TstampNanos> tuple. We also know that the sender and recipient
   250  	// have different public keys.
   251  
   252  	// Create a MessageEntry
   253  	messageEntry := &MessageEntry{
   254  		SenderPublicKey:    txn.PublicKey,
   255  		RecipientPublicKey: txMeta.RecipientPublicKey,
   256  		EncryptedText:      txMeta.EncryptedText,
   257  		TstampNanos:        txMeta.TimestampNanos,
   258  		Version:            1,
   259  	}
   260  
   261  	//Check if message is encrypted with shared secret
   262  	extraV, hasExtraV := txn.ExtraData["V"]
   263  	if hasExtraV {
   264  		Version, _ := Uvarint(extraV)
   265  		messageEntry.Version = uint8(Version)
   266  	}
   267  
   268  	if bav.Postgres != nil {
   269  		message := &PGMessage{
   270  			MessageHash:        txn.Hash(),
   271  			SenderPublicKey:    txn.PublicKey,
   272  			RecipientPublicKey: txMeta.RecipientPublicKey,
   273  			EncryptedText:      txMeta.EncryptedText,
   274  			TimestampNanos:     txMeta.TimestampNanos,
   275  		}
   276  
   277  		bav.setMessageMappings(message)
   278  	} else {
   279  		// Set the mappings in our in-memory map for the MessageEntry.
   280  		bav._setMessageEntryMappings(messageEntry)
   281  	}
   282  
   283  	// Add an operation to the list at the end indicating we've added a message
   284  	// to our data structure.
   285  	utxoOpsForTxn = append(utxoOpsForTxn, &UtxoOperation{
   286  		Type: OperationTypePrivateMessage,
   287  	})
   288  
   289  	return totalInput, totalOutput, utxoOpsForTxn, nil
   290  }
   291  
   292  // TODO: Update for postgres
   293  func (bav *UtxoView) _disconnectPrivateMessage(
   294  	operationType OperationType, currentTxn *MsgDeSoTxn, txnHash *BlockHash,
   295  	utxoOpsForTxn []*UtxoOperation, blockHeight uint32) error {
   296  
   297  	// Verify that the last operation is a PrivateMessage opration
   298  	if len(utxoOpsForTxn) == 0 {
   299  		return fmt.Errorf("_disconnectPrivateMessage: utxoOperations are missing")
   300  	}
   301  	operationIndex := len(utxoOpsForTxn) - 1
   302  	if utxoOpsForTxn[operationIndex].Type != OperationTypePrivateMessage {
   303  		return fmt.Errorf("_disconnectPrivateMessage: Trying to revert "+
   304  			"OperationTypePrivateMessage but found type %v",
   305  			utxoOpsForTxn[operationIndex].Type)
   306  	}
   307  
   308  	// Now we know the txMeta is PrivateMessage
   309  	txMeta := currentTxn.TxnMeta.(*PrivateMessageMetadata)
   310  
   311  	// Get the MessageEntry for the sender in the transaction. If we don't find
   312  	// it or if it has isDeleted=true that's an error.
   313  	senderMessageKey := MakeMessageKey(currentTxn.PublicKey, txMeta.TimestampNanos)
   314  	messageEntry := bav._getMessageEntryForMessageKey(&senderMessageKey)
   315  	if messageEntry == nil || messageEntry.isDeleted {
   316  		return fmt.Errorf("_disconnectPrivateMessage: MessageEntry for "+
   317  			"SenderMessageKey %v was found to be nil or deleted: %v",
   318  			&senderMessageKey, messageEntry)
   319  	}
   320  
   321  	// Verify that the sender and recipient in the entry match the TxnMeta as
   322  	// a sanity check.
   323  	if !reflect.DeepEqual(messageEntry.SenderPublicKey, currentTxn.PublicKey) {
   324  		return fmt.Errorf("_disconnectPrivateMessage: Sender public key on "+
   325  			"MessageEntry was %s but the PublicKey on the txn was %s",
   326  			PkToString(messageEntry.SenderPublicKey, bav.Params),
   327  			PkToString(currentTxn.PublicKey, bav.Params))
   328  	}
   329  	if !reflect.DeepEqual(messageEntry.RecipientPublicKey, txMeta.RecipientPublicKey) {
   330  		return fmt.Errorf("_disconnectPrivateMessage: Recipient public key on "+
   331  			"MessageEntry was %s but the PublicKey on the TxnMeta was %s",
   332  			PkToString(messageEntry.RecipientPublicKey, bav.Params),
   333  			PkToString(txMeta.RecipientPublicKey, bav.Params))
   334  	}
   335  	// Sanity-check that the MessageEntry TstampNanos matches the transaction.
   336  	if messageEntry.TstampNanos != txMeta.TimestampNanos {
   337  		return fmt.Errorf("_disconnectPrivateMessage: TimestampNanos in "+
   338  			"MessageEntry was %d but in transaction it was %d",
   339  			messageEntry.TstampNanos,
   340  			txMeta.TimestampNanos)
   341  	}
   342  	// Sanity-check that the EncryptedText on the MessageEntry matches the transaction
   343  	// just for good measure.
   344  	if !reflect.DeepEqual(messageEntry.EncryptedText, txMeta.EncryptedText) {
   345  		return fmt.Errorf("_disconnectPrivateMessage: EncryptedText in MessageEntry "+
   346  			"did not match EncryptedText in transaction: (%s) != (%s)",
   347  			hex.EncodeToString(messageEntry.EncryptedText),
   348  			hex.EncodeToString(txMeta.EncryptedText))
   349  	}
   350  
   351  	// Now that we are confident the MessageEntry lines up with the transaction we're
   352  	// rolling back, use the entry to delete the mappings for this message.
   353  	bav._deleteMessageEntryMappings(messageEntry)
   354  
   355  	// Now revert the basic transfer with the remaining operations. Cut off
   356  	// the PrivateMessage operation at the end since we just reverted it.
   357  	return bav._disconnectBasicTransfer(
   358  		currentTxn, txnHash, utxoOpsForTxn[:operationIndex], blockHeight)
   359  }