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

     1  package lib
     2  
     3  import (
     4  	"encoding/hex"
     5  	"fmt"
     6  	"github.com/btcsuite/btcd/btcec"
     7  	"github.com/dgraph-io/badger/v3"
     8  	"github.com/stretchr/testify/assert"
     9  	"github.com/stretchr/testify/require"
    10  	"log"
    11  	"os"
    12  	"runtime/pprof"
    13  	"testing"
    14  	"time"
    15  )
    16  
    17  func _swapIdentity(t *testing.T, chain *Blockchain, db *badger.DB,
    18  	params *DeSoParams, feeRateNanosPerKB uint64, updaterPkBase58Check string,
    19  	updaterPrivBase58Check string, fromPublicKey []byte, toPublicKey []byte) (
    20  	_utxoOps []*UtxoOperation, _txn *MsgDeSoTxn, _height uint32, _err error) {
    21  
    22  	assert := assert.New(t)
    23  	require := require.New(t)
    24  	_ = assert
    25  	_ = require
    26  
    27  	updaterPkBytes, _, err := Base58CheckDecode(updaterPkBase58Check)
    28  	require.NoError(err)
    29  
    30  	utxoView, err := NewUtxoView(db, params, nil)
    31  	require.NoError(err)
    32  
    33  	txn, totalInputMake, changeAmountMake, feesMake, err := chain.CreateSwapIdentityTxn(
    34  		updaterPkBytes,
    35  		fromPublicKey,
    36  		toPublicKey,
    37  		feeRateNanosPerKB,
    38  		nil,
    39  		[]*DeSoOutput{})
    40  	if err != nil {
    41  		return nil, nil, 0, err
    42  	}
    43  
    44  	require.Equal(totalInputMake, changeAmountMake+feesMake)
    45  
    46  	// Sign the transaction now that its inputs are set up.
    47  	_signTxn(t, txn, updaterPrivBase58Check)
    48  
    49  	txHash := txn.Hash()
    50  	// Always use height+1 for validation since it's assumed the transaction will
    51  	// get mined into the next block.
    52  	blockHeight := chain.blockTip().Height + 1
    53  	utxoOps, totalInput, totalOutput, fees, err :=
    54  		utxoView.ConnectTransaction(txn, txHash, getTxnSize(*txn), blockHeight, true /*verifySignature*/, false /*ignoreUtxos*/)
    55  	// ConnectTransaction should treat the amount locked as contributing to the
    56  	// output.
    57  	if err != nil {
    58  		return nil, nil, 0, err
    59  	}
    60  	require.Equal(totalInput, totalOutput+fees)
    61  	require.Equal(totalInput, totalInputMake)
    62  
    63  	// We should have one SPEND UtxoOperation for each input, one ADD operation
    64  	// for each output, and one OperationTypeSwapIdentity operation at the end.
    65  	require.Equal(len(txn.TxInputs)+len(txn.TxOutputs)+1, len(utxoOps))
    66  	for ii := 0; ii < len(txn.TxInputs); ii++ {
    67  		require.Equal(OperationTypeSpendUtxo, utxoOps[ii].Type)
    68  	}
    69  	require.Equal(OperationTypeSwapIdentity, utxoOps[len(utxoOps)-1].Type)
    70  
    71  	require.NoError(utxoView.FlushToDb())
    72  
    73  	return utxoOps, txn, blockHeight, nil
    74  }
    75  
    76  func _updateProfile(t *testing.T, chain *Blockchain, db *badger.DB,
    77  	params *DeSoParams, feeRateNanosPerKB uint64, updaterPkBase58Check string,
    78  	updaterPrivBase58Check string, profilePubKey []byte, newUsername string,
    79  	newDescription string, newProfilePic string, newCreatorBasisPoints uint64,
    80  	newStakeMultipleBasisPoints uint64, isHidden bool) (
    81  	_utxoOps []*UtxoOperation, _txn *MsgDeSoTxn, _height uint32, _err error) {
    82  
    83  	assert := assert.New(t)
    84  	require := require.New(t)
    85  	_ = assert
    86  	_ = require
    87  
    88  	updaterPkBytes, _, err := Base58CheckDecode(updaterPkBase58Check)
    89  	require.NoError(err)
    90  
    91  	utxoView, err := NewUtxoView(db, params, nil)
    92  	require.NoError(err)
    93  
    94  	txn, totalInputMake, changeAmountMake, feesMake, err := chain.CreateUpdateProfileTxn(
    95  		updaterPkBytes,
    96  		profilePubKey,
    97  		newUsername,
    98  		newDescription,
    99  		newProfilePic,
   100  		newCreatorBasisPoints,
   101  		newStakeMultipleBasisPoints,
   102  		isHidden,
   103  		0,
   104  		feeRateNanosPerKB,
   105  		nil, /*mempool*/
   106  		[]*DeSoOutput{})
   107  	if err != nil {
   108  		return nil, nil, 0, err
   109  	}
   110  
   111  	require.Equal(totalInputMake, changeAmountMake+feesMake)
   112  
   113  	// Sign the transaction now that its inputs are set up.
   114  	_signTxn(t, txn, updaterPrivBase58Check)
   115  
   116  	txHash := txn.Hash()
   117  	// Always use height+1 for validation since it's assumed the transaction will
   118  	// get mined into the next block.
   119  	blockHeight := chain.blockTip().Height + 1
   120  	utxoOps, totalInput, totalOutput, fees, err :=
   121  		utxoView.ConnectTransaction(txn, txHash, getTxnSize(*txn), blockHeight, true /*verifySignature*/, false /*ignoreUtxos*/)
   122  	// ConnectTransaction should treat the amount locked as contributing to the
   123  	// output.
   124  	if err != nil {
   125  		return nil, nil, 0, err
   126  	}
   127  	require.Equal(totalInput, totalOutput+fees)
   128  	require.Equal(totalInput, totalInputMake)
   129  
   130  	// We should have one SPEND UtxoOperation for each input, one ADD operation
   131  	// for each output, and one OperationTypeUpdateProfile operation at the end.
   132  	require.Equal(len(txn.TxInputs)+len(txn.TxOutputs)+1, len(utxoOps))
   133  	for ii := 0; ii < len(txn.TxInputs); ii++ {
   134  		require.Equal(OperationTypeSpendUtxo, utxoOps[ii].Type)
   135  	}
   136  	require.Equal(OperationTypeUpdateProfile, utxoOps[len(utxoOps)-1].Type)
   137  
   138  	require.NoError(utxoView.FlushToDb())
   139  
   140  	return utxoOps, txn, blockHeight, nil
   141  }
   142  
   143  func _updateProfileWithTestMeta(
   144  	testMeta *TestMeta,
   145  	feeRateNanosPerKB uint64,
   146  	updaterPkBase58Check string,
   147  	updaterPrivBase58Check string,
   148  	profilePubKey []byte,
   149  	newUsername string,
   150  	newDescription string,
   151  	newProfilePic string,
   152  	newCreatorBasisPoints uint64,
   153  	newStakeMultipleBasisPoints uint64,
   154  	isHidden bool) {
   155  
   156  	testMeta.expectedSenderBalances = append(
   157  		testMeta.expectedSenderBalances, _getBalance(testMeta.t, testMeta.chain, nil, updaterPkBase58Check))
   158  
   159  	currentOps, currentTxn, _, err := _updateProfile(
   160  		testMeta.t, testMeta.chain, testMeta.db, testMeta.params,
   161  		feeRateNanosPerKB, updaterPkBase58Check,
   162  		updaterPrivBase58Check, profilePubKey, newUsername,
   163  		newDescription, newProfilePic, newCreatorBasisPoints,
   164  		newStakeMultipleBasisPoints, isHidden)
   165  
   166  	require.NoError(testMeta.t, err)
   167  	testMeta.txnOps = append(testMeta.txnOps, currentOps)
   168  	testMeta.txns = append(testMeta.txns, currentTxn)
   169  }
   170  
   171  func _getAuthorizeDerivedKeyMetadata(t *testing.T, ownerPrivateKey *btcec.PrivateKey,
   172  	params *DeSoParams, expirationBlock uint64, isDeleted bool) (*AuthorizeDerivedKeyMetadata,
   173  	*btcec.PrivateKey) {
   174  	require := require.New(t)
   175  
   176  	// Generate a random derived key pair
   177  	derivedPrivateKey, err := btcec.NewPrivateKey(btcec.S256())
   178  	require.NoError(err, "_getAuthorizeDerivedKeyMetadata: Error generating a derived key pair")
   179  	derivedPublicKey := derivedPrivateKey.PubKey().SerializeCompressed()
   180  
   181  	// Create access signature
   182  	expirationBlockByte := EncodeUint64(expirationBlock)
   183  	accessBytes := append(derivedPublicKey, expirationBlockByte[:]...)
   184  	accessSignature, err := ownerPrivateKey.Sign(Sha256DoubleHash(accessBytes)[:])
   185  	require.NoError(err, "_getAuthorizeDerivedKeyMetadata: Error creating access signature")
   186  
   187  	// Determine operation type
   188  	var operationType AuthorizeDerivedKeyOperationType
   189  	if isDeleted {
   190  		operationType = AuthorizeDerivedKeyOperationNotValid
   191  	} else {
   192  		operationType = AuthorizeDerivedKeyOperationValid
   193  	}
   194  
   195  	return &AuthorizeDerivedKeyMetadata{
   196  		derivedPublicKey,
   197  		expirationBlock,
   198  		operationType,
   199  		accessSignature.Serialize(),
   200  	}, derivedPrivateKey
   201  }
   202  
   203  // Create a new AuthorizeDerivedKey txn and connect it to the utxoView
   204  func _doAuthorizeTxn(t *testing.T, chain *Blockchain, db *badger.DB,
   205  	params *DeSoParams, utxoView *UtxoView, feeRateNanosPerKB uint64, ownerPublicKey []byte,
   206  	derivedPublicKey []byte, derivedPrivBase58Check string, expirationBlock uint64,
   207  	accessSignature []byte, deleteKey bool) (_utxoOps []*UtxoOperation,
   208  	_txn *MsgDeSoTxn, _height uint32, _err error) {
   209  
   210  	assert := assert.New(t)
   211  	require := require.New(t)
   212  	_ = assert
   213  	_ = require
   214  
   215  	txn, totalInput, changeAmount, fees, err := chain.CreateAuthorizeDerivedKeyTxn(
   216  		ownerPublicKey,
   217  		derivedPublicKey,
   218  		expirationBlock,
   219  		accessSignature,
   220  		deleteKey,
   221  		false,
   222  		feeRateNanosPerKB,
   223  		nil, /*mempool*/
   224  		[]*DeSoOutput{})
   225  	if err != nil {
   226  		return nil, nil, 0, err
   227  	}
   228  
   229  	require.Equal(totalInput, changeAmount+fees)
   230  
   231  	// Sign the transaction now that its inputs are set up.
   232  	// We have to set the solution byte because we're signing
   233  	// the transaction with derived key on behalf of the owner.
   234  	_signTxnWithDerivedKey(t, txn, derivedPrivBase58Check)
   235  
   236  	txHash := txn.Hash()
   237  	// Always use height+1 for validation since it's assumed the transaction will
   238  	// get mined into the next block.
   239  	blockHeight := chain.blockTip().Height + 1
   240  	utxoOps, totalInput, totalOutput, fees, err :=
   241  		utxoView.ConnectTransaction(txn, txHash, getTxnSize(*txn), blockHeight, true /*verifySignature*/, false /*ignoreUtxos*/)
   242  	// ConnectTransaction should treat the amount locked as contributing to the
   243  	// output.
   244  	if err != nil {
   245  		return nil, nil, 0, err
   246  	}
   247  	require.Equal(totalInput, totalOutput+fees)
   248  	require.Equal(totalInput, totalInput)
   249  
   250  	// We should have one SPEND UtxoOperation for each input, one ADD operation
   251  	// for each output, and one OperationTypeUpdateProfile operation at the end.
   252  	require.Equal(len(txn.TxInputs)+len(txn.TxOutputs)+1, len(utxoOps))
   253  	for ii := 0; ii < len(txn.TxInputs); ii++ {
   254  		require.Equal(OperationTypeSpendUtxo, utxoOps[ii].Type)
   255  	}
   256  	require.Equal(OperationTypeAuthorizeDerivedKey, utxoOps[len(utxoOps)-1].Type)
   257  
   258  	return utxoOps, txn, blockHeight, nil
   259  }
   260  
   261  const (
   262  	longPic       string = "data:image/jpeg;base64,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"
   263  	shortPic      string = "data:image/jpeg;base64,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"
   264  	otherShortPic string = "data:image/jpeg;base64,/9j/2wCEAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDIBCQkJDAsMGA0NGDIhHCEyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMv/AABEIAGQAZAMBIgACEQEDEQH/xAGiAAABBQEBAQEBAQAAAAAAAAAAAQIDBAUGBwgJCgsQAAIBAwMCBAMFBQQEAAABfQECAwAEEQUSITFBBhNRYQcicRQygZGhCCNCscEVUtHwJDNicoIJChYXGBkaJSYnKCkqNDU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6g4SFhoeIiYqSk5SVlpeYmZqio6Slpqeoqaqys7S1tre4ubrCw8TFxsfIycrS09TV1tfY2drh4uPk5ebn6Onq8fLz9PX29/j5+gEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoLEQACAQIEBAMEBwUEBAABAncAAQIDEQQFITEGEkFRB2FxEyIygQgUQpGhscEJIzNS8BVictEKFiQ04SXxFxgZGiYnKCkqNTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqCg4SFhoeIiYqSk5SVlpeYmZqio6Slpqeoqaqys7S1tre4ubrCw8TFxsfIycrS09TV1tfY2dri4+Tl5ufo6ery8/T19vf4+fr/2gAMAwEAAhEDEQA/APf6KKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAoopGJVSQpYgcAd6AForyO++JmrHUJCgg05bZyj2dxHuckcEOeD/wB8fma7SDxpDH4Stte1OxurRJ3WNIVQyO5Y4UqBzhu2QDz0rSdKUEpPqZQrRnJxj08jqKKwbTxdp17p9/cwR3ZksB+/tGt2SdTjcAEbBJI6etXptasLU2KXU4gkvmCQRyAhmbaWwR2OAevpWZqaFFc5qfjfRtJv5bS5kuD5Gw3M8UDPFbb/ALvmOOFzViz8TQXfiSfQ2sryC5ihadZJkURyxhgu5SGJIJPcCgDbopnmx/N86/L97np9ar6hqVnpdjPe3twkNvAhkkdudq+uBzQBbopkM0c8SyROHRgCCD1p9ABRRRQAUjbtp2kBscZGRS0UAfP/AIkOqN4guzrccn29WAcW0a+XKv8AAU7gHpzkn7pzjFd34hsvEWo/DywXULaSbUlvbeaWOxTEiRrID9N4XqRgZ6V291o+n3t/a31zaxyXNoSYZGHKZ/n+PQ81exSV+rua1JwlFKMUn1fc8dvNEu7jQPE3m+H9WvVvmT+z2vYlkuxMImXe5z8qLwFPUZPFamt6UNU03wxqk3hm6uPsUyw3tvJbKZzCI2XG3PzLvIOPxr07FGKZkeb2R1HQb3WY7Xwvd3cerSQz2URRViRfLVDHMcny9u3pg8dKmvJ9Sk+IUtxbaPqcSHTH02O6EA8tZjJkPnP3B1z+lehYoxQB4gfCeq3Witaaf4fu7G8j0eaDUpJsAX05KlcHJ8w7lZg3vitbU9Ev/FDeJLj+wrqIz6PAlkt7EEYzp5nTk4YZ46dfevWcUYoA5/wetpHoax2miz6SqsN8M1uISz7RlsA8+mfaugoooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKAP/9k="
   265  )
   266  
   267  func TestUpdateProfile(t *testing.T) {
   268  	// For testing purposes, we set the fix block height to be 0 for the ParamUpdaterProfileUpdateFixBlockHeight.
   269  	ParamUpdaterProfileUpdateFixBlockHeight = 0
   270  	UpdateProfileFixBlockHeight = 0
   271  
   272  	assert := assert.New(t)
   273  	require := require.New(t)
   274  	_ = assert
   275  	_ = require
   276  
   277  	chain, params, db := NewLowDifficultyBlockchain()
   278  	mempool, miner := NewTestMiner(t, chain, params, true /*isSender*/)
   279  	// Make m3 a paramUpdater for this test
   280  	params.ParamUpdaterPublicKeys[MakePkMapKey(m3PkBytes)] = true
   281  
   282  	// Mine a few blocks to give the senderPkString some money.
   283  	_, err := miner.MineAndProcessSingleBlock(0 /*threadIndex*/, mempool)
   284  	require.NoError(err)
   285  	_, err = miner.MineAndProcessSingleBlock(0 /*threadIndex*/, mempool)
   286  	require.NoError(err)
   287  	_, err = miner.MineAndProcessSingleBlock(0 /*threadIndex*/, mempool)
   288  	require.NoError(err)
   289  	_, err = miner.MineAndProcessSingleBlock(0 /*threadIndex*/, mempool)
   290  	require.NoError(err)
   291  
   292  	// Setup some convenience functions for the test.
   293  	txnOps := [][]*UtxoOperation{}
   294  	txns := []*MsgDeSoTxn{}
   295  	expectedSenderBalances := []uint64{}
   296  
   297  	// We take the block tip to be the blockchain height rather than the
   298  	// header chain height.
   299  	savedHeight := chain.blockTip().Height + 1
   300  	registerOrTransfer := func(username string,
   301  		senderPk string, recipientPk string, senderPriv string) {
   302  
   303  		expectedSenderBalances = append(expectedSenderBalances, _getBalance(t, chain, nil, senderPk))
   304  
   305  		currentOps, currentTxn, _ := _doBasicTransferWithViewFlush(
   306  			t, chain, db, params, senderPk, recipientPk,
   307  			senderPriv, 70 /*amount to send*/, 11 /*feerate*/)
   308  
   309  		txnOps = append(txnOps, currentOps)
   310  		txns = append(txns, currentTxn)
   311  	}
   312  
   313  	// Fund all the keys.
   314  	registerOrTransfer("", senderPkString, m0Pub, senderPrivString)
   315  	registerOrTransfer("", senderPkString, m1Pub, senderPrivString)
   316  	registerOrTransfer("", senderPkString, m1Pub, senderPrivString)
   317  	registerOrTransfer("", senderPkString, m1Pub, senderPrivString)
   318  	registerOrTransfer("", senderPkString, m1Pub, senderPrivString)
   319  	registerOrTransfer("", senderPkString, m1Pub, senderPrivString)
   320  	registerOrTransfer("", senderPkString, m1Pub, senderPrivString)
   321  	registerOrTransfer("", senderPkString, m2Pub, senderPrivString)
   322  	registerOrTransfer("", senderPkString, m2Pub, senderPrivString)
   323  	registerOrTransfer("", senderPkString, m3Pub, senderPrivString)
   324  	registerOrTransfer("", senderPkString, m3Pub, senderPrivString)
   325  	registerOrTransfer("", senderPkString, m3Pub, senderPrivString)
   326  
   327  	// Fund key to test CreateProfile fee
   328  	registerOrTransfer("", senderPkString, m4Pub, senderPrivString)
   329  
   330  	updateProfile := func(
   331  		feeRateNanosPerKB uint64, updaterPkBase58Check string,
   332  		updaterPrivBase58Check string, profilePubKey []byte, newUsername string,
   333  		newDescription string, newProfilePic string, newCreatorBasisPoints uint64,
   334  		newStakeMultipleBasisPoints uint64, isHidden bool) {
   335  
   336  		expectedSenderBalances = append(expectedSenderBalances, _getBalance(t, chain, nil, updaterPkBase58Check))
   337  
   338  		currentOps, currentTxn, _, err := _updateProfile(
   339  			t, chain, db, params,
   340  			feeRateNanosPerKB, updaterPkBase58Check,
   341  			updaterPrivBase58Check, profilePubKey, newUsername,
   342  			newDescription, newProfilePic, newCreatorBasisPoints,
   343  			newStakeMultipleBasisPoints, isHidden)
   344  
   345  		require.NoError(err)
   346  
   347  		txnOps = append(txnOps, currentOps)
   348  		txns = append(txns, currentTxn)
   349  	}
   350  	_, _, _ = m2Priv, m3Priv, updateProfile
   351  
   352  	updateGlobalParamsEntry := func(
   353  		feeRateNanosPerKB uint64, updaterPkBase58Check string,
   354  		updaterPrivBase58Check string,
   355  		USDCentsPerBitcoinExchangeRate int64,
   356  		minimumNetworkFeeNanosPerKb int64,
   357  		createProfileFeeNanos int64) {
   358  
   359  		expectedSenderBalances = append(expectedSenderBalances, _getBalance(t, chain, nil, updaterPkBase58Check))
   360  
   361  		currentOps, currentTxn, _, err := _updateGlobalParamsEntry(t, chain, db, params,
   362  			feeRateNanosPerKB,
   363  			updaterPkBase58Check,
   364  			updaterPrivBase58Check,
   365  			int64(InitialUSDCentsPerBitcoinExchangeRate),
   366  			minimumNetworkFeeNanosPerKb,
   367  			createProfileFeeNanos,
   368  			0,  /*createNFTFeeNanos*/
   369  			-1, /*maxCopiesPerNFT*/
   370  			true)
   371  		require.NoError(err)
   372  		txnOps = append(txnOps, currentOps)
   373  		txns = append(txns, currentTxn)
   374  	}
   375  
   376  	// ===================================================================================
   377  	// Do some UpdateProfile transactions
   378  	// ===================================================================================
   379  
   380  	// Zero input txn should fail.
   381  	{
   382  		_, _, _, err = _updateProfile(
   383  			t, chain, db, params,
   384  			0,             /*feeRateNanosPerKB*/
   385  			m0Pub,         /*updaterPkBase58Check*/
   386  			m0Priv,        /*updaterPrivBase58Check*/
   387  			[]byte{},      /*profilePubKey*/
   388  			"m0",          /*newUsername*/
   389  			"I am the m0", /*newDescription*/
   390  			shortPic,      /*newProfilePic*/
   391  			10*100,        /*newCreatorBasisPoints*/
   392  			2*100*100,     /*newStakeMultipleBasisPoints*/
   393  			false /*isHidden*/)
   394  		require.Error(err)
   395  		require.Contains(err.Error(), RuleErrorTxnMustHaveAtLeastOneInput)
   396  	}
   397  
   398  	// Username too long should fail.
   399  	{
   400  		badUsername := string(append([]byte("badUsername: "),
   401  			RandomBytes(int32(params.MaxUsernameLengthBytes))...))
   402  		_, _, _, err = _updateProfile(
   403  			t, chain, db, params,
   404  			10,            /*feeRateNanosPerKB*/
   405  			m0Pub,         /*updaterPkBase58Check*/
   406  			m0Priv,        /*updaterPrivBase58Check*/
   407  			[]byte{},      /*profilePubKey*/
   408  			badUsername,   /*newUsername*/
   409  			"I am the m0", /*newDescription*/
   410  			shortPic,      /*newProfilePic*/
   411  			10*100,        /*newCreatorBasisPoints*/
   412  			2*100*100,     /*newStakeMultipleBasisPoints*/
   413  			false /*isHidden*/)
   414  		require.Error(err)
   415  		require.Contains(err.Error(), RuleErrorProfileUsernameTooLong)
   416  	}
   417  
   418  	// Description too long should fail.
   419  	{
   420  		badDescription := string(append([]byte("badDescription: "),
   421  			RandomBytes(int32(params.MaxUserDescriptionLengthBytes))...))
   422  		_, _, _, err = _updateProfile(
   423  			t, chain, db, params,
   424  			2,              /*feeRateNanosPerKB*/
   425  			m0Pub,          /*updaterPkBase58Check*/
   426  			m0Priv,         /*updaterPrivBase58Check*/
   427  			[]byte{},       /*profilePubKey*/
   428  			"m0",           /*newUsername*/
   429  			badDescription, /*newDescription*/
   430  			shortPic,       /*newProfilePic*/
   431  			10*100,         /*newCreatorBasisPoints*/
   432  			2*100*100,      /*newStakeMultipleBasisPoints*/
   433  			false /*isHidden*/)
   434  		require.Error(err)
   435  		require.Contains(err.Error(), RuleErrorProfileDescriptionTooLong)
   436  	}
   437  
   438  	// Profile pic too long should fail.
   439  	{
   440  		_, _, _, err = _updateProfile(
   441  			t, chain, db, params,
   442  			1,             /*feeRateNanosPerKB*/
   443  			m0Pub,         /*updaterPkBase58Check*/
   444  			m0Priv,        /*updaterPrivBase58Check*/
   445  			[]byte{},      /*profilePubKey*/
   446  			"m0",          /*newUsername*/
   447  			"i am the m0", /*newDescription*/
   448  			longPic,       /*newProfilePic*/
   449  			10*100,        /*newCreatorBasisPoints*/
   450  			2*100*100,     /*newStakeMultipleBasisPoints*/
   451  			false /*isHidden*/)
   452  		require.Error(err)
   453  		require.Contains(err.Error(), RuleErrorMaxProfilePicSize)
   454  	}
   455  
   456  	// Stake multiple too large should fail long too long should fail.
   457  	{
   458  		_, _, _, err = _updateProfile(
   459  			t, chain, db, params,
   460  			1,             /*feeRateNanosPerKB*/
   461  			m0Pub,         /*updaterPkBase58Check*/
   462  			m0Priv,        /*updaterPrivBase58Check*/
   463  			[]byte{},      /*profilePubKey*/
   464  			"m0",          /*newUsername*/
   465  			"i am the m0", /*newDescription*/
   466  			shortPic,      /*newProfilePic*/
   467  			10*100,        /*newCreatorBasisPoints*/
   468  			100*100*100,   /*newStakeMultipleBasisPoints*/
   469  			false /*isHidden*/)
   470  		require.Error(err)
   471  		require.Contains(err.Error(), RuleErrorProfileStakeMultipleSize)
   472  	}
   473  
   474  	// Stake multiple too small should fail long too long should fail.
   475  	{
   476  		_, _, _, err = _updateProfile(
   477  			t, chain, db, params,
   478  			1,             /*feeRateNanosPerKB*/
   479  			m0Pub,         /*updaterPkBase58Check*/
   480  			m0Priv,        /*updaterPrivBase58Check*/
   481  			[]byte{},      /*profilePubKey*/
   482  			"m0",          /*newUsername*/
   483  			"i am the m0", /*newDescription*/
   484  			shortPic,      /*newProfilePic*/
   485  			10*100,        /*newCreatorBasisPoints*/
   486  			.99*100*100,   /*newStakeMultipleBasisPoints*/
   487  			false /*isHidden*/)
   488  		require.Error(err)
   489  		require.Contains(err.Error(), RuleErrorProfileStakeMultipleSize)
   490  	}
   491  
   492  	// Creator percentage too large should fail.
   493  	{
   494  		_, _, _, err = _updateProfile(
   495  			t, chain, db, params,
   496  			1,             /*feeRateNanosPerKB*/
   497  			m0Pub,         /*updaterPkBase58Check*/
   498  			m0Priv,        /*updaterPrivBase58Check*/
   499  			[]byte{},      /*profilePubKey*/
   500  			"m0",          /*newUsername*/
   501  			"i am the m0", /*newDescription*/
   502  			shortPic,      /*newProfilePic*/
   503  			101*100,       /*newCreatorBasisPoints*/
   504  			1.25*100*100,  /*newStakeMultipleBasisPoints*/
   505  			false /*isHidden*/)
   506  		require.Error(err)
   507  		require.Contains(err.Error(), RuleErrorProfileCreatorPercentageSize)
   508  	}
   509  
   510  	// Invalid profile public key should fail.
   511  	{
   512  		_, _, _, err = _updateProfile(
   513  			t, chain, db, params,
   514  			1,               /*feeRateNanosPerKB*/
   515  			m0Pub,           /*updaterPkBase58Check*/
   516  			m0Priv,          /*updaterPrivBase58Check*/
   517  			RandomBytes(33), /*profilePubKey*/
   518  			"m0",            /*newUsername*/
   519  			"i am the m0",   /*newDescription*/
   520  			shortPic,        /*newProfilePic*/
   521  			10*100,          /*newCreatorBasisPoints*/
   522  			1.25*100*100,    /*newStakeMultipleBasisPoints*/
   523  			false /*isHidden*/)
   524  		require.Error(err)
   525  		// This returned RuleErrorProfilePubKeyNotAuthorized for me once
   526  		// "ConnectTransaction: : _connectUpdateProfile: ... RuleErrorProfilePubKeyNotAuthorized"
   527  		require.Contains(err.Error(), RuleErrorProfileBadPublicKey)
   528  	}
   529  
   530  	// Profile public key that is not authorized should fail.
   531  	{
   532  		_, _, _, err = _updateProfile(
   533  			t, chain, db, params,
   534  			1,             /*feeRateNanosPerKB*/
   535  			m0Pub,         /*updaterPkBase58Check*/
   536  			m0Priv,        /*updaterPrivBase58Check*/
   537  			m1PkBytes,     /*profilePubKey*/
   538  			"m0",          /*newUsername*/
   539  			"i am the m0", /*newDescription*/
   540  			shortPic,      /*newProfilePic*/
   541  			10*100,        /*newCreatorBasisPoints*/
   542  			1.25*100*100,  /*newStakeMultipleBasisPoints*/
   543  			false /*isHidden*/)
   544  		require.Error(err)
   545  		require.Contains(err.Error(), RuleErrorProfilePubKeyNotAuthorized)
   546  	}
   547  
   548  	// A simple registration should succeed
   549  	{
   550  		updateProfile(
   551  			1,             /*feeRateNanosPerKB*/
   552  			m0Pub,         /*updaterPkBase58Check*/
   553  			m0Priv,        /*updaterPrivBase58Check*/
   554  			[]byte{},      /*profilePubKey*/
   555  			"m0",          /*newUsername*/
   556  			"i am the m0", /*newDescription*/
   557  			shortPic,      /*newProfilePic*/
   558  			10*100,        /*newCreatorBasisPoints*/
   559  			1.25*100*100,  /*newStakeMultipleBasisPoints*/
   560  			false /*isHidden*/)
   561  	}
   562  
   563  	// Username that does not match our regex should fail
   564  	{
   565  		_, _, _, err = _updateProfile(
   566  			t, chain, db, params,
   567  			10,            /*feeRateNanosPerKB*/
   568  			m1Pub,         /*updaterPkBase58Check*/
   569  			m1Priv,        /*updaterPrivBase58Check*/
   570  			[]byte{},      /*profilePubKey*/
   571  			"m0\x00",      /*newUsername*/
   572  			"i am the m0", /*newDescription*/
   573  			shortPic,      /*newProfilePic*/
   574  			10*100,        /*newCreatorBasisPoints*/
   575  			1.25*100*100,  /*newStakeMultipleBasisPoints*/
   576  			false /*isHidden*/)
   577  		require.Error(err)
   578  		require.Contains(err.Error(), RuleErrorInvalidUsername)
   579  
   580  		_, _, _, err = _updateProfile(
   581  			t, chain, db, params,
   582  			10,                /*feeRateNanosPerKB*/
   583  			m1Pub,             /*updaterPkBase58Check*/
   584  			m1Priv,            /*updaterPrivBase58Check*/
   585  			[]byte{},          /*profilePubKey*/
   586  			"m0 with a space", /*newUsername*/
   587  			"i am the m0",     /*newDescription*/
   588  			shortPic,          /*newProfilePic*/
   589  			10*100,            /*newCreatorBasisPoints*/
   590  			1.25*100*100,      /*newStakeMultipleBasisPoints*/
   591  			false /*isHidden*/)
   592  		require.Error(err)
   593  		require.Contains(err.Error(), RuleErrorInvalidUsername)
   594  
   595  		_, _, _, err = _updateProfile(
   596  			t, chain, db, params,
   597  			10,                  /*feeRateNanosPerKB*/
   598  			m1Pub,               /*updaterPkBase58Check*/
   599  			m1Priv,              /*updaterPrivBase58Check*/
   600  			[]byte{},            /*profilePubKey*/
   601  			"m0TraillingSpace ", /*newUsername*/
   602  			"i am the m0",       /*newDescription*/
   603  			shortPic,            /*newProfilePic*/
   604  			10*100,              /*newCreatorBasisPoints*/
   605  			1.25*100*100,        /*newStakeMultipleBasisPoints*/
   606  			false /*isHidden*/)
   607  		require.Error(err)
   608  		require.Contains(err.Error(), RuleErrorInvalidUsername)
   609  
   610  		_, _, _, err = _updateProfile(
   611  			t, chain, db, params,
   612  			10,            /*feeRateNanosPerKB*/
   613  			m1Pub,         /*updaterPkBase58Check*/
   614  			m1Priv,        /*updaterPrivBase58Check*/
   615  			[]byte{},      /*profilePubKey*/
   616  			"m0-Hyphen",   /*newUsername*/
   617  			"i am the m0", /*newDescription*/
   618  			shortPic,      /*newProfilePic*/
   619  			10*100,        /*newCreatorBasisPoints*/
   620  			1.25*100*100,  /*newStakeMultipleBasisPoints*/
   621  			false /*isHidden*/)
   622  		require.Error(err)
   623  		require.Contains(err.Error(), RuleErrorInvalidUsername)
   624  
   625  		_, _, _, err = _updateProfile(
   626  			t, chain, db, params,
   627  			10,                    /*feeRateNanosPerKB*/
   628  			m1Pub,                 /*updaterPkBase58Check*/
   629  			m1Priv,                /*updaterPrivBase58Check*/
   630  			[]byte{},              /*profilePubKey*/
   631  			" m0SpaceAtBeginning", /*newUsername*/
   632  			"i am the m0",         /*newDescription*/
   633  			shortPic,              /*newProfilePic*/
   634  			10*100,                /*newCreatorBasisPoints*/
   635  			1.25*100*100,          /*newStakeMultipleBasisPoints*/
   636  			false /*isHidden*/)
   637  		require.Error(err)
   638  		require.Contains(err.Error(), RuleErrorInvalidUsername)
   639  	}
   640  
   641  	// Trying to take an already-registered username should fail.
   642  	{
   643  		_, _, _, err = _updateProfile(
   644  			t, chain, db, params,
   645  			1,             /*feeRateNanosPerKB*/
   646  			m1Pub,         /*updaterPkBase58Check*/
   647  			m1Priv,        /*updaterPrivBase58Check*/
   648  			[]byte{},      /*profilePubKey*/
   649  			"m0",          /*newUsername*/
   650  			"i am the m0", /*newDescription*/
   651  			shortPic,      /*newProfilePic*/
   652  			10*100,        /*newCreatorBasisPoints*/
   653  			1.25*100*100,  /*newStakeMultipleBasisPoints*/
   654  			false /*isHidden*/)
   655  		require.Error(err)
   656  		require.Contains(err.Error(), RuleErrorProfileUsernameExists)
   657  
   658  		// The username should be case-insensitive so creating a duplicate
   659  		// with different casing should fail.
   660  		_, _, _, err = _updateProfile(
   661  			t, chain, db, params,
   662  			1,             /*feeRateNanosPerKB*/
   663  			m1Pub,         /*updaterPkBase58Check*/
   664  			m1Priv,        /*updaterPrivBase58Check*/
   665  			[]byte{},      /*profilePubKey*/
   666  			"M0",          /*newUsername*/
   667  			"i am the m0", /*newDescription*/
   668  			shortPic,      /*newProfilePic*/
   669  			10*100,        /*newCreatorBasisPoints*/
   670  			1.25*100*100,  /*newStakeMultipleBasisPoints*/
   671  			false /*isHidden*/)
   672  		require.Error(err)
   673  		require.Contains(err.Error(), RuleErrorProfileUsernameExists)
   674  
   675  		// Register m1 and then try to steal the username
   676  		updateProfile(
   677  			1,             /*feeRateNanosPerKB*/
   678  			m1Pub,         /*updaterPkBase58Check*/
   679  			m1Priv,        /*updaterPrivBase58Check*/
   680  			[]byte{},      /*profilePubKey*/
   681  			"m1",          /*newUsername*/
   682  			"i am the m1", /*newDescription*/
   683  			shortPic,      /*newProfilePic*/
   684  			10*100,        /*newCreatorBasisPoints*/
   685  			1.25*100*100,  /*newStakeMultipleBasisPoints*/
   686  			false /*isHidden*/)
   687  
   688  		_, _, _, err = _updateProfile(
   689  			t, chain, db, params,
   690  			1,             /*feeRateNanosPerKB*/
   691  			m1Pub,         /*updaterPkBase58Check*/
   692  			m1Priv,        /*updaterPrivBase58Check*/
   693  			[]byte{},      /*profilePubKey*/
   694  			"m0",          /*newUsername*/
   695  			"i am the m0", /*newDescription*/
   696  			shortPic,      /*newProfilePic*/
   697  			10*100,        /*newCreatorBasisPoints*/
   698  			1.25*100*100,  /*newStakeMultipleBasisPoints*/
   699  			false /*isHidden*/)
   700  		require.Error(err)
   701  		require.Contains(err.Error(), RuleErrorProfileUsernameExists)
   702  
   703  		// The username should be case-insensitive so creating a duplicate
   704  		// with different casing should fail.
   705  		_, _, _, err = _updateProfile(
   706  			t, chain, db, params,
   707  			1,             /*feeRateNanosPerKB*/
   708  			m1Pub,         /*updaterPkBase58Check*/
   709  			m1Priv,        /*updaterPrivBase58Check*/
   710  			[]byte{},      /*profilePubKey*/
   711  			"M0",          /*newUsername*/
   712  			"i am the m0", /*newDescription*/
   713  			shortPic,      /*newProfilePic*/
   714  			10*100,        /*newCreatorBasisPoints*/
   715  			1.25*100*100,  /*newStakeMultipleBasisPoints*/
   716  			false /*isHidden*/)
   717  		require.Error(err)
   718  		require.Contains(err.Error(), RuleErrorProfileUsernameExists)
   719  
   720  		// The username should be case-insensitive so creating a duplicate
   721  		// with different casing should fail.
   722  		_, _, _, err = _updateProfile(
   723  			t, chain, db, params,
   724  			1,             /*feeRateNanosPerKB*/
   725  			m0Pub,         /*updaterPkBase58Check*/
   726  			m0Priv,        /*updaterPrivBase58Check*/
   727  			[]byte{},      /*profilePubKey*/
   728  			"M1",          /*newUsername*/
   729  			"i am the m0", /*newDescription*/
   730  			shortPic,      /*newProfilePic*/
   731  			10*100,        /*newCreatorBasisPoints*/
   732  			1.25*100*100,  /*newStakeMultipleBasisPoints*/
   733  			false /*isHidden*/)
   734  		require.Error(err)
   735  		require.Contains(err.Error(), RuleErrorProfileUsernameExists)
   736  	}
   737  
   738  	// Register m2 (should succeed)
   739  	{
   740  		updateProfile(
   741  			1,             /*feeRateNanosPerKB*/
   742  			m2Pub,         /*updaterPkBase58Check*/
   743  			m2Priv,        /*updaterPrivBase58Check*/
   744  			[]byte{},      /*profilePubKey*/
   745  			"m2",          /*newUsername*/
   746  			"i am the m2", /*newDescription*/
   747  			shortPic,      /*newProfilePic*/
   748  			10*100,        /*newCreatorBasisPoints*/
   749  			1.25*100*100,  /*newStakeMultipleBasisPoints*/
   750  			false /*isHidden*/)
   751  	}
   752  
   753  	// Leaving username, description, and pic blank should result in a noop.
   754  	{
   755  		updateProfile(
   756  			10,           /*feeRateNanosPerKB*/
   757  			m2Pub,        /*updaterPkBase58Check*/
   758  			m2Priv,       /*updaterPrivBase58Check*/
   759  			[]byte{},     /*profilePubKey*/
   760  			"",           /*newUsername*/
   761  			"",           /*newDescription*/
   762  			"",           /*newProfilePic*/
   763  			10*100,       /*newCreatorBasisPoints*/
   764  			1.25*100*100, /*newStakeMultipleBasisPoints*/
   765  			false /*isHidden*/)
   766  	}
   767  
   768  	// An update followed by a reversion should result in no change.
   769  	{
   770  		updateProfile(
   771  			1,                    /*feeRateNanosPerKB*/
   772  			m2Pub,                /*updaterPkBase58Check*/
   773  			m2Priv,               /*updaterPrivBase58Check*/
   774  			[]byte{},             /*profilePubKey*/
   775  			"m2_update",          /*newUsername*/
   776  			"i am the m2 update", /*newDescription*/
   777  			shortPic+"woohoo",    /*newProfilePic*/
   778  			15*100,               /*newCreatorBasisPoints*/
   779  			1.7*100*100,          /*newStakeMultipleBasisPoints*/
   780  			true /*isHidden*/)
   781  
   782  		updateProfile(
   783  			1,             /*feeRateNanosPerKB*/
   784  			m2Pub,         /*updaterPkBase58Check*/
   785  			m2Priv,        /*updaterPrivBase58Check*/
   786  			[]byte{},      /*profilePubKey*/
   787  			"m2",          /*newUsername*/
   788  			"i am the m2", /*newDescription*/
   789  			shortPic,      /*newProfilePic*/
   790  			10*100,        /*newCreatorBasisPoints*/
   791  			1.25*100*100,  /*newStakeMultipleBasisPoints*/
   792  			false /*isHidden*/)
   793  	}
   794  
   795  	// A normal user updating their profile should succeed.
   796  	{
   797  		updateProfile(
   798  			1,                  /*feeRateNanosPerKB*/
   799  			m1Pub,              /*updaterPkBase58Check*/
   800  			m1Priv,             /*updaterPrivBase58Check*/
   801  			[]byte{},           /*profilePubKey*/
   802  			"m1_updated_by_m1", /*newUsername*/
   803  			"m1 updated by m1", /*newDescription*/
   804  			otherShortPic,      /*newProfilePic*/
   805  			12*100,             /*newCreatorBasisPoints*/
   806  			1.6*100*100,        /*newStakeMultipleBasisPoints*/
   807  			true /*isHidden*/)
   808  	}
   809  
   810  	// Normal user updating another user's profile should fail.
   811  	{
   812  		_, _, _, err = _updateProfile(
   813  			t, chain, db, params,
   814  			1,                /*feeRateNanosPerKB*/
   815  			m1Pub,            /*updaterPkBase58Check*/
   816  			m1Priv,           /*updaterPrivBase58Check*/
   817  			m0PkBytes,        /*profilePubKey*/
   818  			"m0_actually_m1", /*newUsername*/
   819  			"i am the m1",    /*newDescription*/
   820  			shortPic,         /*newProfilePic*/
   821  			10*100,           /*newCreatorBasisPoints*/
   822  			1.25*100*100,     /*newStakeMultipleBasisPoints*/
   823  			false /*isHidden*/)
   824  		require.Error(err)
   825  		require.Contains(err.Error(), RuleErrorProfilePubKeyNotAuthorized)
   826  	}
   827  
   828  	// ParamUpdater updating another user's profile should succeed.
   829  	{
   830  		updateProfile(
   831  			1,                            /*feeRateNanosPerKB*/
   832  			m3Pub,                        /*updaterPkBase58Check*/
   833  			m3Priv,                       /*updaterPrivBase58Check*/
   834  			m0PkBytes,                    /*profilePubKey*/
   835  			"m0_paramUpdater",            /*newUsername*/
   836  			"m0 updated by paramUpdater", /*newDescription*/
   837  			otherShortPic,                /*newProfilePic*/
   838  			11*100,                       /*newCreatorBasisPoints*/
   839  			1.5*100*100,                  /*newStakeMultipleBasisPoints*/
   840  			true /*isHidden*/)
   841  	}
   842  
   843  	// ParamUpdater creating another user's profile should succeed.
   844  	{
   845  		updateProfile(
   846  			1,                            /*feeRateNanosPerKB*/
   847  			m3Pub,                        /*updaterPkBase58Check*/
   848  			m3Priv,                       /*updaterPrivBase58Check*/
   849  			m5PkBytes,                    /*profilePubKey*/
   850  			"m5_paramUpdater",            /*newUsername*/
   851  			"m5 created by paramUpdater", /*newDescription*/
   852  			otherShortPic,                /*newProfilePic*/
   853  			11*100,                       /*newCreatorBasisPoints*/
   854  			1.5*100*100,                  /*newStakeMultipleBasisPoints*/
   855  			false /*isHidden*/)
   856  	}
   857  
   858  	// Create Profile Fee and Minimum Network Fee tests
   859  	{
   860  		// Set the create profile fee to 100 nanos
   861  		updateGlobalParamsEntry(
   862  			100,
   863  			m3Pub,
   864  			m3Priv,
   865  			int64(InitialUSDCentsPerBitcoinExchangeRate),
   866  			0,
   867  			100)
   868  
   869  		// m4 does not have enough to create a profile including fee
   870  		_, _, _, err = _updateProfile(
   871  			t, chain, db, params,
   872  			1,
   873  			m4Pub,
   874  			m4Priv,
   875  			m4PkBytes,
   876  			"m4_username",
   877  			"m4 desc",
   878  			shortPic,
   879  			11*100,
   880  			1.5*100*100,
   881  			false)
   882  		require.Error(err)
   883  		require.Contains(err.Error(), RuleErrorCreateProfileTxnOutputExceedsInput)
   884  		// Reduce the create profile fee, Set minimum network fee to 10 nanos per kb
   885  
   886  		updateGlobalParamsEntry(
   887  			100,
   888  			m3Pub,
   889  			m3Priv,
   890  			int64(InitialUSDCentsPerBitcoinExchangeRate),
   891  			5,
   892  			1)
   893  
   894  		// Update profile fails as the fee is too low
   895  		_, _, _, err = _updateProfile(
   896  			t, chain, db, params,
   897  			1,
   898  			m4Pub,
   899  			m4Priv,
   900  			m4PkBytes,
   901  			"m4_username",
   902  			"m4 description",
   903  			otherShortPic,
   904  			11*100,
   905  			1.5*100*100,
   906  			false,
   907  		)
   908  		require.Error(err)
   909  		require.Contains(err.Error(), RuleErrorTxnFeeBelowNetworkMinimum)
   910  		// Update succeeds because fee is high enough and user has enough to meet fee.
   911  		updateProfile(
   912  			10,
   913  			m4Pub,
   914  			m4Priv,
   915  			m4PkBytes,
   916  			"m4",
   917  			"m4 description",
   918  			otherShortPic,
   919  			11*100,
   920  			1.5*100*100,
   921  			false,
   922  		)
   923  		// Reset the create profile fee to 0 nanos (no fee) and set network minimum back to 0.
   924  		updateGlobalParamsEntry(
   925  			100,
   926  			m3Pub,
   927  			m3Priv,
   928  			int64(InitialUSDCentsPerBitcoinExchangeRate),
   929  			0,
   930  			0)
   931  
   932  	}
   933  
   934  	// user0
   935  	// m0Pub, m0_updated_by_paramUpdater, m0 updated by paramUpdater, otherShortPic, 11*100, 1.5*100*100, true
   936  	// user1
   937  	// m1Pub, m1_updated_by_m1, m1 updated by m1, otherShortPic, 12*100, 1.6*100*100, true
   938  	// user2
   939  	// m2Pub, m2, i am m2, 10*100, 1.25*100*100
   940  	// user5
   941  	// m5Pub, m5_paramUpdater, m5 created by paramUpdater, otherShortPic, 11*100, 1.5*100*100, false
   942  	checkProfilesExist := func() {
   943  		utxoView, err := NewUtxoView(db, params, nil)
   944  		require.NoError(err)
   945  		profileEntriesByPublicKey, _, _, _, err := utxoView.GetAllProfiles(nil)
   946  		require.NoError(err)
   947  		// 3 profiles from seed txns
   948  		require.Equal(8, len(profileEntriesByPublicKey))
   949  		{
   950  			m0Entry, m0Exists := profileEntriesByPublicKey[MakePkMapKey(m0PkBytes)]
   951  			require.True(m0Exists)
   952  			require.Equal(string(m0Entry.Username), "m0_paramUpdater")
   953  			require.Equal(string(m0Entry.Description), "m0 updated by paramUpdater")
   954  			require.Equal(string(m0Entry.ProfilePic), otherShortPic)
   955  			require.Equal(int64(m0Entry.CreatorBasisPoints), int64(11*100))
   956  			require.True(m0Entry.IsHidden)
   957  		}
   958  		{
   959  			m1Entry, m1Exists := profileEntriesByPublicKey[MakePkMapKey(m1PkBytes)]
   960  			require.True(m1Exists)
   961  			require.Equal(string(m1Entry.Username), "m1_updated_by_m1")
   962  			require.Equal(string(m1Entry.Description), "m1 updated by m1")
   963  			require.Equal(string(m1Entry.ProfilePic), otherShortPic)
   964  			require.Equal(int64(m1Entry.CreatorBasisPoints), int64(12*100))
   965  			require.True(m1Entry.IsHidden)
   966  		}
   967  		{
   968  			m2Entry, m2Exists := profileEntriesByPublicKey[MakePkMapKey(m2PkBytes)]
   969  			require.True(m2Exists)
   970  			require.Equal(string(m2Entry.Username), "m2")
   971  			require.Equal(string(m2Entry.Description), "i am the m2")
   972  			require.Equal(string(m2Entry.ProfilePic), shortPic)
   973  			require.Equal(int64(m2Entry.CreatorBasisPoints), int64(10*100))
   974  			require.False(m2Entry.IsHidden)
   975  		}
   976  		{
   977  			m4Entry, m4Exists := profileEntriesByPublicKey[MakePkMapKey(m4PkBytes)]
   978  			require.True(m4Exists)
   979  			require.Equal(string(m4Entry.Username), "m4")
   980  			require.Equal(string(m4Entry.Description), "m4 description")
   981  			require.Equal(string(m4Entry.ProfilePic), otherShortPic)
   982  			require.Equal(int64(m4Entry.CreatorBasisPoints), int64(11*100))
   983  			require.False(m4Entry.IsHidden)
   984  		}
   985  		{
   986  			m5Entry, m5Exists := profileEntriesByPublicKey[MakePkMapKey(m5PkBytes)]
   987  			require.True(m5Exists)
   988  			require.Equal(string(m5Entry.Username), "m5_paramUpdater")
   989  			require.Equal(string(m5Entry.Description), "m5 created by paramUpdater")
   990  			require.Equal(string(m5Entry.ProfilePic), otherShortPic)
   991  			require.Equal(int64(m5Entry.CreatorBasisPoints), int64(11*100))
   992  			require.False(m5Entry.IsHidden)
   993  		}
   994  	}
   995  	checkProfilesExist()
   996  
   997  	checkProfilesDeleted := func() {
   998  		utxoView, err := NewUtxoView(db, params, nil)
   999  		require.NoError(err)
  1000  		profileEntriesByPublicKey, _, _, _, err := utxoView.GetAllProfiles(nil)
  1001  		require.NoError(err)
  1002  		// 3 remain because of the seed txns
  1003  		require.Equal(3, len(profileEntriesByPublicKey))
  1004  	}
  1005  
  1006  	// ===================================================================================
  1007  	// Finish it off with some transactions
  1008  	// ===================================================================================
  1009  	registerOrTransfer("", senderPkString, m0Pub, senderPrivString)
  1010  	registerOrTransfer("", senderPkString, m0Pub, senderPrivString)
  1011  	registerOrTransfer("", senderPkString, m0Pub, senderPrivString)
  1012  	registerOrTransfer("", senderPkString, m0Pub, senderPrivString)
  1013  	registerOrTransfer("", senderPkString, m0Pub, senderPrivString)
  1014  	registerOrTransfer("", senderPkString, m0Pub, senderPrivString)
  1015  	registerOrTransfer("", senderPkString, m1Pub, senderPrivString)
  1016  	registerOrTransfer("", senderPkString, m1Pub, senderPrivString)
  1017  	registerOrTransfer("", senderPkString, m1Pub, senderPrivString)
  1018  	registerOrTransfer("", senderPkString, m1Pub, senderPrivString)
  1019  	registerOrTransfer("", senderPkString, m1Pub, senderPrivString)
  1020  	registerOrTransfer("", senderPkString, m1Pub, senderPrivString)
  1021  	registerOrTransfer("", m0Pub, m1Pub, m0Priv)
  1022  	registerOrTransfer("", m1Pub, m0Pub, m1Priv)
  1023  	registerOrTransfer("", m1Pub, m0Pub, m1Priv)
  1024  	registerOrTransfer("", m0Pub, m1Pub, m0Priv)
  1025  	registerOrTransfer("", m1Pub, m0Pub, m1Priv)
  1026  	registerOrTransfer("", m0Pub, m1Pub, m0Priv)
  1027  	registerOrTransfer("", m1Pub, m0Pub, m1Priv)
  1028  	registerOrTransfer("", m0Pub, m1Pub, m0Priv)
  1029  	registerOrTransfer("", m1Pub, m0Pub, m1Priv)
  1030  	registerOrTransfer("", m1Pub, m0Pub, m1Priv)
  1031  	registerOrTransfer("", m0Pub, m1Pub, m0Priv)
  1032  	registerOrTransfer("", m0Pub, m1Pub, m0Priv)
  1033  	registerOrTransfer("", m0Pub, m1Pub, m0Priv)
  1034  
  1035  	// Roll back all of the above using the utxoOps from each.
  1036  	for ii := 0; ii < len(txnOps); ii++ {
  1037  		backwardIter := len(txnOps) - 1 - ii
  1038  		currentOps := txnOps[backwardIter]
  1039  		currentTxn := txns[backwardIter]
  1040  		fmt.Printf("Disconnecting transaction with type %v index %d (going backwards)\n", currentTxn.TxnMeta.GetTxnType(), backwardIter)
  1041  
  1042  		utxoView, err := NewUtxoView(db, params, nil)
  1043  		require.NoError(err)
  1044  
  1045  		currentHash := currentTxn.Hash()
  1046  		err = utxoView.DisconnectTransaction(currentTxn, currentHash, currentOps, savedHeight)
  1047  		require.NoError(err)
  1048  
  1049  		require.NoError(utxoView.FlushToDb())
  1050  
  1051  		// After disconnecting, the balances should be restored to what they
  1052  		// were before this transaction was applied.
  1053  		require.Equal(expectedSenderBalances[backwardIter], _getBalance(t, chain, nil, PkToStringTestnet(currentTxn.PublicKey)))
  1054  	}
  1055  
  1056  	// Verify that all the profiles have been deleted.
  1057  	checkProfilesDeleted()
  1058  
  1059  	// Apply all the transactions to a mempool object and make sure we don't get any
  1060  	// errors. Verify the balances align as we go.
  1061  	for ii, tx := range txns {
  1062  		// See comment above on this transaction.
  1063  		fmt.Printf("Adding txn %d of type %v to mempool\n", ii, tx.TxnMeta.GetTxnType())
  1064  
  1065  		require.Equal(expectedSenderBalances[ii], _getBalance(
  1066  			t, chain, mempool, PkToStringTestnet(tx.PublicKey)))
  1067  
  1068  		_, err := mempool.ProcessTransaction(tx, false, false, 0, true)
  1069  		require.NoError(err, "Problem adding transaction %d to mempool: %v", ii, tx)
  1070  	}
  1071  
  1072  	// Apply all the transactions to a view and flush the view to the db.
  1073  	utxoView, err := NewUtxoView(db, params, nil)
  1074  	require.NoError(err)
  1075  	for ii, txn := range txns {
  1076  		fmt.Printf("Adding txn %v of type %v to UtxoView\n", ii, txn.TxnMeta.GetTxnType())
  1077  
  1078  		// Always use height+1 for validation since it's assumed the transaction will
  1079  		// get mined into the next block.
  1080  		txHash := txn.Hash()
  1081  		blockHeight := chain.blockTip().Height + 1
  1082  		_, _, _, _, err :=
  1083  			utxoView.ConnectTransaction(txn, txHash, getTxnSize(*txn), blockHeight, true /*verifySignature*/, false /*ignoreUtxos*/)
  1084  		require.NoError(err)
  1085  	}
  1086  	// Flush the utxoView after having added all the transactions.
  1087  	require.NoError(utxoView.FlushToDb())
  1088  
  1089  	// Verify the profiles exist.
  1090  	checkProfilesExist()
  1091  
  1092  	// Disonnect the transactions from a single view in the same way as above
  1093  	// i.e. without flushing each time.
  1094  	utxoView2, err := NewUtxoView(db, params, nil)
  1095  	require.NoError(err)
  1096  	for ii := 0; ii < len(txnOps); ii++ {
  1097  		backwardIter := len(txnOps) - 1 - ii
  1098  		fmt.Printf("Disconnecting transaction with index %d (going backwards)\n", backwardIter)
  1099  		currentOps := txnOps[backwardIter]
  1100  		currentTxn := txns[backwardIter]
  1101  
  1102  		currentHash := currentTxn.Hash()
  1103  		err = utxoView2.DisconnectTransaction(currentTxn, currentHash, currentOps, savedHeight)
  1104  		require.NoError(err)
  1105  	}
  1106  	require.NoError(utxoView2.FlushToDb())
  1107  	require.Equal(expectedSenderBalances[0], _getBalance(t, chain, nil, senderPkString))
  1108  
  1109  	// Verify that all the profiles have been deleted.
  1110  	checkProfilesDeleted()
  1111  
  1112  	// All the txns should be in the mempool already so mining a block should put
  1113  	// all those transactions in it.
  1114  	block, err := miner.MineAndProcessSingleBlock(0 /*threadIndex*/, mempool)
  1115  	require.NoError(err)
  1116  	// Add one for the block reward. Now we have a meaty block.
  1117  	require.Equal(len(txnOps)+1, len(block.Txns))
  1118  
  1119  	// Roll back the block and make sure we don't hit any errors.
  1120  	{
  1121  		utxoView, err := NewUtxoView(db, params, nil)
  1122  		require.NoError(err)
  1123  
  1124  		// Fetch the utxo operations for the block we're detaching. We need these
  1125  		// in order to be able to detach the block.
  1126  		hash, err := block.Header.Hash()
  1127  		require.NoError(err)
  1128  		utxoOps, err := GetUtxoOperationsForBlock(db, hash)
  1129  		require.NoError(err)
  1130  
  1131  		// Compute the hashes for all the transactions.
  1132  		txHashes, err := ComputeTransactionHashes(block.Txns)
  1133  		require.NoError(err)
  1134  		require.NoError(utxoView.DisconnectBlock(block, txHashes, utxoOps))
  1135  
  1136  		// Flushing the view after applying and rolling back should work.
  1137  		require.NoError(utxoView.FlushToDb())
  1138  	}
  1139  
  1140  	// Verify that all the profiles have been deleted.
  1141  	checkProfilesDeleted()
  1142  }
  1143  
  1144  func TestSpamUpdateProfile(t *testing.T) {
  1145  	assert := assert.New(t)
  1146  	require := require.New(t)
  1147  	_, _ = assert, require
  1148  
  1149  	f, err := os.Create("/tmp/perf")
  1150  	if err != nil {
  1151  		log.Fatal(err)
  1152  	}
  1153  	pprof.StartCPUProfile(f)
  1154  	defer pprof.StopCPUProfile()
  1155  
  1156  	chain, params, _ := NewLowDifficultyBlockchain()
  1157  	mempool, miner := NewTestMiner(t, chain, params, true /*isSender*/)
  1158  	feeRateNanosPerKB := uint64(11)
  1159  	_, _ = mempool, miner
  1160  
  1161  	numTxns := 250
  1162  	for ii := 0; ii < numTxns; ii++ {
  1163  		fmt.Println("Creating txns: ", ii)
  1164  		startTimeCreateTxn := time.Now()
  1165  		moneyPkBytes, _, _ := Base58CheckDecode(moneyPkString)
  1166  		txn, _, _, _, err := chain.CreateUpdateProfileTxn(
  1167  			moneyPkBytes,
  1168  			nil,
  1169  			"money",
  1170  			fmt.Sprintf("this is a new description: %v", ii),
  1171  			"profile pic",
  1172  			5000,  /*CreatorBasisPoints*/
  1173  			12500, /*StakeMultiple*/
  1174  			false, /*isHidden*/
  1175  			0,
  1176  			feeRateNanosPerKB, /*feeRateNanosPerKB*/
  1177  			mempool,           /*mempool*/
  1178  			[]*DeSoOutput{})
  1179  		require.NoError(err)
  1180  		_signTxn(t, txn, moneyPrivString)
  1181  		fmt.Printf("Creating txn took: %v seconds\n", time.Since(startTimeCreateTxn).Seconds())
  1182  
  1183  		fmt.Println("Running txns through mempool: ", ii)
  1184  		startTimeMempoolAdd := time.Now()
  1185  		mempoolTxsAdded, err := mempool.processTransaction(
  1186  			txn, true /*allowUnconnectedTxn*/, true /*rateLimit*/, 0, /*peerID*/
  1187  			true /*verifySignatures*/)
  1188  		require.NoError(err)
  1189  		require.Equal(1, len(mempoolTxsAdded))
  1190  		fmt.Printf("Adding to mempool took: %v seconds\n", time.Since(startTimeMempoolAdd).Seconds())
  1191  	}
  1192  }
  1193  
  1194  func TestSwapIdentityNOOPCreatorCoinBuySimple(t *testing.T) {
  1195  
  1196  	creatorCoinTests := []*_CreatorCoinTestData{
  1197  		// Create a profile for m0
  1198  		{
  1199  			TxnType:                      TxnTypeUpdateProfile,
  1200  			UpdaterPublicKeyBase58Check:  m0Pub,
  1201  			UpdaterPrivateKeyBase58Check: m0Priv,
  1202  			ProfilePublicKeyBase58Check:  m0Pub,
  1203  			ProfileUsername:              "m0",
  1204  			ProfileDescription:           "i am m0",
  1205  			ProfilePic:                   "m0 profile pic",
  1206  			ProfileCreatorBasisPoints:    2500,
  1207  			ProfileIsHidden:              false,
  1208  
  1209  			SkipChecks: true,
  1210  		},
  1211  		// Have m1 buy some of m0's coins
  1212  		{
  1213  			// These are the transaction params
  1214  			UpdaterPublicKeyBase58Check:  m1Pub,
  1215  			UpdaterPrivateKeyBase58Check: m1Priv,
  1216  			ProfilePublicKeyBase58Check:  m0Pub,
  1217  			OperationType:                CreatorCoinOperationTypeBuy,
  1218  			DeSoToSellNanos:              1271123456,
  1219  			CreatorCoinToSellNanos:       0,
  1220  			DeSoToAddNanos:               0,
  1221  			MinDeSoExpectedNanos:         0,
  1222  			MinCreatorCoinExpectedNanos:  0,
  1223  
  1224  			// These are the expectations
  1225  			CoinsInCirculationNanos: 10832150315,
  1226  			DeSoLockedNanos:         1270996343,
  1227  			CoinWatermarkNanos:      10832150315,
  1228  			m0CCBalance:             2708037578,
  1229  			m0HasPurchased:          false,
  1230  			m1CCBalance:             8124112737,
  1231  			m1HasPurchased:          true,
  1232  			m2CCBalance:             0,
  1233  			m2HasPurchased:          false,
  1234  			m0DeSoBalance:           5999999998,
  1235  			m1DeSoBalance:           4728876542,
  1236  			m2DeSoBalance:           6000000000,
  1237  		},
  1238  		// Have m2 buy some of m0's coins
  1239  		{
  1240  			// These are the transaction params
  1241  			UpdaterPublicKeyBase58Check:  m2Pub,
  1242  			UpdaterPrivateKeyBase58Check: m2Priv,
  1243  			ProfilePublicKeyBase58Check:  m0Pub,
  1244  			OperationType:                CreatorCoinOperationTypeBuy,
  1245  			DeSoToSellNanos:              1172373183,
  1246  			CreatorCoinToSellNanos:       0,
  1247  			DeSoToAddNanos:               0,
  1248  			MinDeSoExpectedNanos:         0,
  1249  			MinCreatorCoinExpectedNanos:  0,
  1250  
  1251  			// These are the expectations
  1252  			CoinsInCirculationNanos: 13468606753,
  1253  			DeSoLockedNanos:         2443252288,
  1254  			CoinWatermarkNanos:      13468606753,
  1255  			m0CCBalance:             3367151687,
  1256  			m0HasPurchased:          false,
  1257  			m1CCBalance:             8124112737,
  1258  			m1HasPurchased:          true,
  1259  			m2CCBalance:             1977342329,
  1260  			m2HasPurchased:          true,
  1261  			m0DeSoBalance:           5999999998,
  1262  			m1DeSoBalance:           4728876542,
  1263  			m2DeSoBalance:           4827626815,
  1264  		},
  1265  		// Have m1 sell half of their stake
  1266  		{
  1267  			// These are the transaction params
  1268  			UpdaterPublicKeyBase58Check:  m1Pub,
  1269  			UpdaterPrivateKeyBase58Check: m1Priv,
  1270  			ProfilePublicKeyBase58Check:  m0Pub,
  1271  			OperationType:                CreatorCoinOperationTypeSell,
  1272  			DeSoToSellNanos:              0,
  1273  			CreatorCoinToSellNanos:       4123456789,
  1274  			DeSoToAddNanos:               0,
  1275  			MinDeSoExpectedNanos:         0,
  1276  			MinCreatorCoinExpectedNanos:  0,
  1277  
  1278  			// These are the expectations
  1279  			CoinsInCirculationNanos: 9345149964,
  1280  			DeSoLockedNanos:         816129494,
  1281  			CoinWatermarkNanos:      13468606753,
  1282  			m0CCBalance:             3367151687,
  1283  			m0HasPurchased:          false,
  1284  			m1CCBalance:             4000655948,
  1285  			m1HasPurchased:          true,
  1286  			m2CCBalance:             1977342329,
  1287  			m2HasPurchased:          true,
  1288  			m0DeSoBalance:           5999999998,
  1289  			m1DeSoBalance:           6355836621,
  1290  			m2DeSoBalance:           4827626815,
  1291  			m3DeSoBalance:           6000000000,
  1292  		},
  1293  		// Swap m0 and m3
  1294  		// State after swapping:
  1295  		// m0Pk: m3 profile
  1296  		// m3Pk: m0 profile (the one with the profile)
  1297  		{
  1298  			TxnType:       TxnTypeSwapIdentity,
  1299  			FromPublicKey: m0PkBytes,
  1300  			ToPublicKey:   m3PkBytes,
  1301  			// This is the creator whose coins we are testing the balances of.
  1302  			// Normally it's m0, but because we swapped m0 for m3 we should test
  1303  			// that one instead.
  1304  			ProfilePublicKeyBase58Check: m3Pub,
  1305  
  1306  			// These are the expectations
  1307  			CoinsInCirculationNanos: 9345149964,
  1308  			DeSoLockedNanos:         816129494,
  1309  			CoinWatermarkNanos:      13468606753,
  1310  			m0CCBalance:             0, // Should go to zero because it belongs to m3 now
  1311  			m0HasPurchased:          false,
  1312  			m1CCBalance:             4000655948,
  1313  			m1HasPurchased:          true,
  1314  			m2CCBalance:             1977342329,
  1315  			m2HasPurchased:          true,
  1316  			m3CCBalance:             3367151687,
  1317  			m3HasPurchased:          false,
  1318  			m0DeSoBalance:           5999999998,
  1319  			m1DeSoBalance:           6355836621,
  1320  			m2DeSoBalance:           4827626815,
  1321  			m3DeSoBalance:           6000000000,
  1322  		},
  1323  		// Swap m3 and m1
  1324  		// State after swapping:
  1325  		// m0Pk: m3 profile
  1326  		// m1Pk: m0 profile (the one with the profile)
  1327  		// m3Pk: m1 profile
  1328  		{
  1329  			TxnType:       TxnTypeSwapIdentity,
  1330  			FromPublicKey: m3PkBytes,
  1331  			ToPublicKey:   m1PkBytes,
  1332  			// This is the creator whose coins we are testing the balances of.
  1333  			// Normally it's m0, but because we swapped m0 for m3 we should test
  1334  			// that one instead.
  1335  			ProfilePublicKeyBase58Check: m1Pub,
  1336  
  1337  			// These are the expectations
  1338  			CoinsInCirculationNanos: 9345149964,
  1339  			DeSoLockedNanos:         816129494,
  1340  			CoinWatermarkNanos:      13468606753,
  1341  			m0CCBalance:             0, // m0 still has zero because they got a dummy profile
  1342  			m0HasPurchased:          false,
  1343  			m1CCBalance:             3367151687, // This becomes what m3 had a moment ago.
  1344  			m1HasPurchased:          false,
  1345  			m2CCBalance:             1977342329,
  1346  			m2HasPurchased:          true,
  1347  			m3CCBalance:             4000655948, // This becomes what m1 had a moment ago.
  1348  			m3HasPurchased:          true,
  1349  			m0DeSoBalance:           5999999998,
  1350  			m1DeSoBalance:           6355836621,
  1351  			m2DeSoBalance:           4827626815,
  1352  			m3DeSoBalance:           6000000000,
  1353  		},
  1354  		// Swap m0 and m1. Should restore m0's profile to it.
  1355  		// State after swapping:
  1356  		// m0Pk: m0 profile (the one with the profile)
  1357  		// m1Pk: m3 profile
  1358  		// m3Pk: m1 profile
  1359  		{
  1360  			TxnType:       TxnTypeSwapIdentity,
  1361  			FromPublicKey: m0PkBytes,
  1362  			ToPublicKey:   m1PkBytes,
  1363  			// This is the creator whose coins we are testing the balances of.
  1364  			// Normally it's m0, but because we swapped m0 for m3 we should test
  1365  			// that one instead.
  1366  			ProfilePublicKeyBase58Check: m0Pub,
  1367  
  1368  			// These are the expectations
  1369  			CoinsInCirculationNanos: 9345149964,
  1370  			DeSoLockedNanos:         816129494,
  1371  			CoinWatermarkNanos:      13468606753,
  1372  			m0CCBalance:             3367151687, // m0 should be back to normal
  1373  			m0HasPurchased:          false,
  1374  			m1CCBalance:             0, // m1 is the zero now since it took the empty profile from m0
  1375  			m1HasPurchased:          false,
  1376  			m2CCBalance:             1977342329,
  1377  			m2HasPurchased:          true,
  1378  			m3CCBalance:             4000655948, // This is still what m1 started with.
  1379  			m3HasPurchased:          true,
  1380  			m0DeSoBalance:           5999999998,
  1381  			m1DeSoBalance:           6355836621,
  1382  			m2DeSoBalance:           4827626815,
  1383  			m3DeSoBalance:           6000000000,
  1384  		},
  1385  		// Swap m1 and m3. Should restore everything back to normal.
  1386  		// State after swapping:
  1387  		// m0Pk: m0 profile
  1388  		// m1Pk: m1 profile (the one with the profile)
  1389  		// m3Pk: m3 profile
  1390  		{
  1391  			TxnType:       TxnTypeSwapIdentity,
  1392  			FromPublicKey: m1PkBytes,
  1393  			ToPublicKey:   m3PkBytes,
  1394  			// This is the creator whose coins we are testing the balances of.
  1395  			// Normally it's m0, but because we swapped m0 for m3 we should test
  1396  			// that one instead.
  1397  			ProfilePublicKeyBase58Check: m0Pub,
  1398  
  1399  			// These are the expectations
  1400  			CoinsInCirculationNanos: 9345149964,
  1401  			DeSoLockedNanos:         816129494,
  1402  			CoinWatermarkNanos:      13468606753,
  1403  			m0CCBalance:             3367151687,
  1404  			m0HasPurchased:          false,
  1405  			m1CCBalance:             4000655948,
  1406  			m1HasPurchased:          true,
  1407  			m2CCBalance:             1977342329,
  1408  			m2HasPurchased:          true,
  1409  			m3CCBalance:             0, // This goes back to zero as we started with.
  1410  			m3HasPurchased:          false,
  1411  			m0DeSoBalance:           5999999998,
  1412  			m1DeSoBalance:           6355836621,
  1413  			m2DeSoBalance:           4827626815,
  1414  			m3DeSoBalance:           6000000000,
  1415  		},
  1416  		// Have m2 sell all of their stake
  1417  		{
  1418  			// These are the transaction params
  1419  			UpdaterPublicKeyBase58Check:  m2Pub,
  1420  			UpdaterPrivateKeyBase58Check: m2Priv,
  1421  			ProfilePublicKeyBase58Check:  m0Pub,
  1422  			OperationType:                CreatorCoinOperationTypeSell,
  1423  			DeSoToSellNanos:              0,
  1424  			CreatorCoinToSellNanos:       1977342329,
  1425  			DeSoToAddNanos:               0,
  1426  			MinDeSoExpectedNanos:         0,
  1427  			MinCreatorCoinExpectedNanos:  0,
  1428  
  1429  			// These are the expectations
  1430  			CoinsInCirculationNanos: 7367807635,
  1431  			DeSoLockedNanos:         399958612,
  1432  			CoinWatermarkNanos:      13468606753,
  1433  			m0CCBalance:             3367151687,
  1434  			m0HasPurchased:          false,
  1435  			m1CCBalance:             4000655948,
  1436  			m1HasPurchased:          true,
  1437  			m2CCBalance:             0,
  1438  			m2HasPurchased:          false,
  1439  			m0DeSoBalance:           5999999998,
  1440  			m1DeSoBalance:           6355836621,
  1441  			m2DeSoBalance:           5243756077,
  1442  		},
  1443  		// Have m1 buy more, m0 should receive 25% of the minted coins as a founders reward
  1444  		{
  1445  			// These are the transaction params
  1446  			UpdaterPublicKeyBase58Check:  m1Pub,
  1447  			UpdaterPrivateKeyBase58Check: m1Priv,
  1448  			ProfilePublicKeyBase58Check:  m0Pub,
  1449  			OperationType:                CreatorCoinOperationTypeBuy,
  1450  			DeSoToSellNanos:              2123456789,
  1451  			CreatorCoinToSellNanos:       0,
  1452  			DeSoToAddNanos:               0,
  1453  			MinDeSoExpectedNanos:         0,
  1454  			MinCreatorCoinExpectedNanos:  0,
  1455  
  1456  			// These are the expectations
  1457  			CoinsInCirculationNanos: 13613944261,
  1458  			DeSoLockedNanos:         2523203055,
  1459  			CoinWatermarkNanos:      13613944261,
  1460  			m0CCBalance:             4928685843,
  1461  			m0HasPurchased:          false,
  1462  			m1CCBalance:             8685258418,
  1463  			m1HasPurchased:          true,
  1464  			m2CCBalance:             0,
  1465  			m2HasPurchased:          false,
  1466  			m0DeSoBalance:           5999999998,
  1467  			m1DeSoBalance:           4232379830,
  1468  			m2DeSoBalance:           5243756077,
  1469  		},
  1470  
  1471  		// Have m1 sell the rest of their stake
  1472  		{
  1473  			// These are the transaction params
  1474  			UpdaterPublicKeyBase58Check:  m1Pub,
  1475  			UpdaterPrivateKeyBase58Check: m1Priv,
  1476  			ProfilePublicKeyBase58Check:  m0Pub,
  1477  			OperationType:                CreatorCoinOperationTypeSell,
  1478  			DeSoToSellNanos:              0,
  1479  			CreatorCoinToSellNanos:       8685258418,
  1480  			DeSoToAddNanos:               0,
  1481  			MinDeSoExpectedNanos:         0,
  1482  			MinCreatorCoinExpectedNanos:  0,
  1483  
  1484  			// These are the expectations
  1485  			CoinsInCirculationNanos: 4928685843,
  1486  			DeSoLockedNanos:         119727407,
  1487  			CoinWatermarkNanos:      13613944261,
  1488  			m0CCBalance:             4928685843,
  1489  			m0HasPurchased:          false,
  1490  			m1CCBalance:             0,
  1491  			m1HasPurchased:          false,
  1492  			m2CCBalance:             0,
  1493  			m2HasPurchased:          false,
  1494  			m0DeSoBalance:           5999999998,
  1495  			m1DeSoBalance:           6635615128,
  1496  			m2DeSoBalance:           5243756077,
  1497  		},
  1498  
  1499  		// Have m0 sell all of their stake except leave 1 DeSo locked
  1500  		{
  1501  			// These are the transaction params
  1502  			UpdaterPublicKeyBase58Check:  m0Pub,
  1503  			UpdaterPrivateKeyBase58Check: m0Priv,
  1504  			ProfilePublicKeyBase58Check:  m0Pub,
  1505  			OperationType:                CreatorCoinOperationTypeSell,
  1506  			DeSoToSellNanos:              0,
  1507  			CreatorCoinToSellNanos:       4925685829,
  1508  			DeSoToAddNanos:               0,
  1509  			MinDeSoExpectedNanos:         0,
  1510  			MinCreatorCoinExpectedNanos:  0,
  1511  
  1512  			// These are the expectations
  1513  			CoinsInCirculationNanos: 3000014,
  1514  			DeSoLockedNanos:         1,
  1515  			CoinWatermarkNanos:      13613944261,
  1516  			m0CCBalance:             3000014,
  1517  			m0HasPurchased:          false,
  1518  			m1CCBalance:             0,
  1519  			m1HasPurchased:          false,
  1520  			m2CCBalance:             0,
  1521  			m2HasPurchased:          false,
  1522  			m0DeSoBalance:           6119715429,
  1523  			m1DeSoBalance:           6635615128,
  1524  			m2DeSoBalance:           5243756077,
  1525  		},
  1526  
  1527  		{
  1528  			// Have m0 sell all of their remaining stake except for 1 CreatorCoin nano
  1529  			// This will trigger an autosell.
  1530  			UpdaterPublicKeyBase58Check:  m0Pub,
  1531  			UpdaterPrivateKeyBase58Check: m0Priv,
  1532  			ProfilePublicKeyBase58Check:  m0Pub,
  1533  			OperationType:                CreatorCoinOperationTypeSell,
  1534  			DeSoToSellNanos:              0,
  1535  			CreatorCoinToSellNanos:       3000013,
  1536  			DeSoToAddNanos:               0,
  1537  			MinDeSoExpectedNanos:         0,
  1538  			MinCreatorCoinExpectedNanos:  0,
  1539  
  1540  			// These are the expectations
  1541  			CoinsInCirculationNanos: 0,
  1542  			DeSoLockedNanos:         0,
  1543  			CoinWatermarkNanos:      13613944261,
  1544  			m0CCBalance:             0,
  1545  			m0HasPurchased:          false,
  1546  			m1CCBalance:             0,
  1547  			m1HasPurchased:          false,
  1548  			m2CCBalance:             0,
  1549  			m2HasPurchased:          false,
  1550  			m0DeSoBalance:           6119715427,
  1551  			m1DeSoBalance:           6635615128,
  1552  			m2DeSoBalance:           5243756077,
  1553  		},
  1554  
  1555  		// Have m1 buy a little more, m0 should receieve some
  1556  		{
  1557  			// These are the transaction params
  1558  			UpdaterPublicKeyBase58Check:  m1Pub,
  1559  			UpdaterPrivateKeyBase58Check: m1Priv,
  1560  			ProfilePublicKeyBase58Check:  m0Pub,
  1561  			OperationType:                CreatorCoinOperationTypeBuy,
  1562  			DeSoToSellNanos:              2123456789,
  1563  			CreatorCoinToSellNanos:       0,
  1564  			DeSoToAddNanos:               0,
  1565  			MinDeSoExpectedNanos:         0,
  1566  			MinCreatorCoinExpectedNanos:  0,
  1567  
  1568  			// These are the expectations
  1569  			CoinsInCirculationNanos: 12852863707,
  1570  			DeSoLockedNanos:         2123244443,
  1571  			CoinWatermarkNanos:      13613944261,
  1572  			m0CCBalance:             3213215926,
  1573  			m0HasPurchased:          false,
  1574  			m1CCBalance:             9639647781,
  1575  			m1HasPurchased:          true,
  1576  			m2CCBalance:             0,
  1577  			m2HasPurchased:          false,
  1578  			m0DeSoBalance:           6119715427,
  1579  			m1DeSoBalance:           4512158337,
  1580  			m2DeSoBalance:           5243756077,
  1581  		},
  1582  
  1583  		// Have m1 sell their creator coins. m0 should be the only one left with coins.
  1584  		// Meaning m0 is effectively being left with their founders reward, even after all
  1585  		// their supporters have sold.
  1586  		{
  1587  			// These are the transaction params
  1588  			UpdaterPublicKeyBase58Check:  m1Pub,
  1589  			UpdaterPrivateKeyBase58Check: m1Priv,
  1590  			ProfilePublicKeyBase58Check:  m0Pub,
  1591  			OperationType:                CreatorCoinOperationTypeSell,
  1592  			DeSoToSellNanos:              0,
  1593  			CreatorCoinToSellNanos:       9639647781,
  1594  			DeSoToAddNanos:               0,
  1595  			MinDeSoExpectedNanos:         0,
  1596  			MinCreatorCoinExpectedNanos:  0,
  1597  
  1598  			// These are the expectations
  1599  			CoinsInCirculationNanos: 3213215926,
  1600  			DeSoLockedNanos:         33175681,
  1601  			CoinWatermarkNanos:      13613944261,
  1602  			m0CCBalance:             3213215926,
  1603  			m0HasPurchased:          false,
  1604  			m1CCBalance:             0,
  1605  			m1HasPurchased:          false,
  1606  			m2CCBalance:             0,
  1607  			m2HasPurchased:          false,
  1608  			m0DeSoBalance:           6119715427,
  1609  			m1DeSoBalance:           6602018090,
  1610  			m2DeSoBalance:           5243756077,
  1611  		},
  1612  	}
  1613  
  1614  	_helpTestCreatorCoinBuySell(t, creatorCoinTests, false)
  1615  }
  1616  
  1617  func TestSwapIdentityCreatorCoinBuySimple(t *testing.T) {
  1618  	// Set up a blockchain
  1619  	assert := assert.New(t)
  1620  	require := require.New(t)
  1621  	_, _ = assert, require
  1622  
  1623  	creatorCoinTests := []*_CreatorCoinTestData{
  1624  		// Create a profile for m0
  1625  		{
  1626  			TxnType:                      TxnTypeUpdateProfile,
  1627  			UpdaterPublicKeyBase58Check:  m0Pub,
  1628  			UpdaterPrivateKeyBase58Check: m0Priv,
  1629  			ProfilePublicKeyBase58Check:  m0Pub,
  1630  			ProfileUsername:              "m0",
  1631  			ProfileDescription:           "i am m0",
  1632  			ProfilePic:                   "m0 profile pic",
  1633  			ProfileCreatorBasisPoints:    2500,
  1634  			ProfileIsHidden:              false,
  1635  
  1636  			SkipChecks: true,
  1637  		},
  1638  		// Have m1 buy some of m0's coins
  1639  		{
  1640  			// These are the transaction params
  1641  			UpdaterPublicKeyBase58Check:  m1Pub,
  1642  			UpdaterPrivateKeyBase58Check: m1Priv,
  1643  			ProfilePublicKeyBase58Check:  m0Pub,
  1644  			OperationType:                CreatorCoinOperationTypeBuy,
  1645  			DeSoToSellNanos:              1271123456,
  1646  			CreatorCoinToSellNanos:       0,
  1647  			DeSoToAddNanos:               0,
  1648  			MinDeSoExpectedNanos:         0,
  1649  			MinCreatorCoinExpectedNanos:  0,
  1650  
  1651  			// These are the expectations
  1652  			CoinsInCirculationNanos: 10832150315,
  1653  			DeSoLockedNanos:         1270996343,
  1654  			CoinWatermarkNanos:      10832150315,
  1655  			m0CCBalance:             2708037578,
  1656  			m0HasPurchased:          false,
  1657  			m1CCBalance:             8124112737,
  1658  			m1HasPurchased:          true,
  1659  			m2CCBalance:             0,
  1660  			m2HasPurchased:          false,
  1661  			m0DeSoBalance:           5999999998,
  1662  			m1DeSoBalance:           4728876542,
  1663  			m2DeSoBalance:           6000000000,
  1664  		},
  1665  		// Have m2 buy some of m0's coins
  1666  		{
  1667  			// These are the transaction params
  1668  			UpdaterPublicKeyBase58Check:  m2Pub,
  1669  			UpdaterPrivateKeyBase58Check: m2Priv,
  1670  			ProfilePublicKeyBase58Check:  m0Pub,
  1671  			OperationType:                CreatorCoinOperationTypeBuy,
  1672  			DeSoToSellNanos:              1172373183,
  1673  			CreatorCoinToSellNanos:       0,
  1674  			DeSoToAddNanos:               0,
  1675  			MinDeSoExpectedNanos:         0,
  1676  			MinCreatorCoinExpectedNanos:  0,
  1677  
  1678  			// These are the expectations
  1679  			CoinsInCirculationNanos: 13468606753,
  1680  			DeSoLockedNanos:         2443252288,
  1681  			CoinWatermarkNanos:      13468606753,
  1682  			m0CCBalance:             3367151687,
  1683  			m0HasPurchased:          false,
  1684  			m1CCBalance:             8124112737,
  1685  			m1HasPurchased:          true,
  1686  			m2CCBalance:             1977342329,
  1687  			m2HasPurchased:          true,
  1688  			m0DeSoBalance:           5999999998,
  1689  			m1DeSoBalance:           4728876542,
  1690  			m2DeSoBalance:           4827626815,
  1691  		},
  1692  		// Have m1 sell half of their stake
  1693  		{
  1694  			// These are the transaction params
  1695  			UpdaterPublicKeyBase58Check:  m1Pub,
  1696  			UpdaterPrivateKeyBase58Check: m1Priv,
  1697  			ProfilePublicKeyBase58Check:  m0Pub,
  1698  			OperationType:                CreatorCoinOperationTypeSell,
  1699  			DeSoToSellNanos:              0,
  1700  			CreatorCoinToSellNanos:       4123456789,
  1701  			DeSoToAddNanos:               0,
  1702  			MinDeSoExpectedNanos:         0,
  1703  			MinCreatorCoinExpectedNanos:  0,
  1704  
  1705  			// These are the expectations
  1706  			CoinsInCirculationNanos: 9345149964,
  1707  			DeSoLockedNanos:         816129494,
  1708  			CoinWatermarkNanos:      13468606753,
  1709  			m0CCBalance:             3367151687,
  1710  			m0HasPurchased:          false,
  1711  			m1CCBalance:             4000655948,
  1712  			m1HasPurchased:          true,
  1713  			m2CCBalance:             1977342329,
  1714  			m2HasPurchased:          true,
  1715  			m0DeSoBalance:           5999999998,
  1716  			m1DeSoBalance:           6355836621,
  1717  			m2DeSoBalance:           4827626815,
  1718  		},
  1719  
  1720  		// Swap m0 and m3
  1721  		{
  1722  			TxnType:       TxnTypeSwapIdentity,
  1723  			FromPublicKey: m0PkBytes,
  1724  			ToPublicKey:   m3PkBytes,
  1725  			// This is the creator whose coins we are testing the balances of.
  1726  			// Normally it's m0, but because we swapped m0 for m3 we should test
  1727  			// that one instead.
  1728  			ProfilePublicKeyBase58Check: m3Pub,
  1729  
  1730  			// These are the expectations
  1731  			CoinsInCirculationNanos: 9345149964,
  1732  			DeSoLockedNanos:         816129494,
  1733  			CoinWatermarkNanos:      13468606753,
  1734  			m0CCBalance:             0, // Should go to zero because it belongs to m3 now
  1735  			m0HasPurchased:          false,
  1736  			m1CCBalance:             4000655948,
  1737  			m1HasPurchased:          true,
  1738  			m2CCBalance:             1977342329,
  1739  			m2HasPurchased:          true,
  1740  			m3CCBalance:             3367151687,
  1741  			m3HasPurchased:          false,
  1742  			m0DeSoBalance:           5999999998,
  1743  			m1DeSoBalance:           6355836621,
  1744  			m2DeSoBalance:           4827626815,
  1745  		},
  1746  
  1747  		// Have m2 sell all of their stake
  1748  		{
  1749  			// These are the transaction params
  1750  			UpdaterPublicKeyBase58Check:  m2Pub,
  1751  			UpdaterPrivateKeyBase58Check: m2Priv,
  1752  			ProfilePublicKeyBase58Check:  m3Pub,
  1753  			OperationType:                CreatorCoinOperationTypeSell,
  1754  			DeSoToSellNanos:              0,
  1755  			CreatorCoinToSellNanos:       1977342329,
  1756  			DeSoToAddNanos:               0,
  1757  			MinDeSoExpectedNanos:         0,
  1758  			MinCreatorCoinExpectedNanos:  0,
  1759  
  1760  			// These are the expectations
  1761  			CoinsInCirculationNanos: 7367807635,
  1762  			DeSoLockedNanos:         399958612,
  1763  			CoinWatermarkNanos:      13468606753,
  1764  			m0CCBalance:             0,
  1765  			m0HasPurchased:          false,
  1766  			m1CCBalance:             4000655948,
  1767  			m1HasPurchased:          true,
  1768  			m2CCBalance:             0,
  1769  			m2HasPurchased:          false,
  1770  			m3CCBalance:             3367151687,
  1771  			m3HasPurchased:          false,
  1772  			m0DeSoBalance:           5999999998,
  1773  			m1DeSoBalance:           6355836621,
  1774  			m2DeSoBalance:           5243756077,
  1775  		},
  1776  		// Have m1 buy more, m3 should receieve a founders reward
  1777  		{
  1778  			// These are the transaction params
  1779  			UpdaterPublicKeyBase58Check:  m1Pub,
  1780  			UpdaterPrivateKeyBase58Check: m1Priv,
  1781  			ProfilePublicKeyBase58Check:  m3Pub,
  1782  			OperationType:                CreatorCoinOperationTypeBuy,
  1783  			DeSoToSellNanos:              2123456789,
  1784  			CreatorCoinToSellNanos:       0,
  1785  			DeSoToAddNanos:               0,
  1786  			MinDeSoExpectedNanos:         0,
  1787  			MinCreatorCoinExpectedNanos:  0,
  1788  
  1789  			// These are the expectations
  1790  			CoinsInCirculationNanos: 13613944261,
  1791  			DeSoLockedNanos:         2523203055,
  1792  			CoinWatermarkNanos:      13613944261,
  1793  			m0CCBalance:             0,
  1794  			m0HasPurchased:          false,
  1795  			m1CCBalance:             8685258418,
  1796  			m1HasPurchased:          true,
  1797  			m2CCBalance:             0,
  1798  			m2HasPurchased:          false,
  1799  			m3CCBalance:             4928685843,
  1800  			m3HasPurchased:          false,
  1801  			m0DeSoBalance:           5999999998,
  1802  			m1DeSoBalance:           4232379830,
  1803  			m2DeSoBalance:           5243756077,
  1804  		},
  1805  
  1806  		// Have m1 sell the rest of their stake
  1807  		{
  1808  			// These are the transaction params
  1809  			UpdaterPublicKeyBase58Check:  m1Pub,
  1810  			UpdaterPrivateKeyBase58Check: m1Priv,
  1811  			ProfilePublicKeyBase58Check:  m3Pub,
  1812  			OperationType:                CreatorCoinOperationTypeSell,
  1813  			DeSoToSellNanos:              0,
  1814  			CreatorCoinToSellNanos:       8685258418,
  1815  			DeSoToAddNanos:               0,
  1816  			MinDeSoExpectedNanos:         0,
  1817  			MinCreatorCoinExpectedNanos:  0,
  1818  
  1819  			// These are the expectations
  1820  			CoinsInCirculationNanos: 4928685843,
  1821  			DeSoLockedNanos:         119727407,
  1822  			CoinWatermarkNanos:      13613944261,
  1823  			m0CCBalance:             0,
  1824  			m0HasPurchased:          false,
  1825  			m1CCBalance:             0,
  1826  			m1HasPurchased:          false,
  1827  			m2CCBalance:             0,
  1828  			m2HasPurchased:          false,
  1829  			m3CCBalance:             4928685843,
  1830  			m3HasPurchased:          false,
  1831  			m0DeSoBalance:           5999999998,
  1832  			m1DeSoBalance:           6635615128,
  1833  			m2DeSoBalance:           5243756077,
  1834  		},
  1835  
  1836  		// Have m3 sell all of their stake except leave 1 DeSo locked
  1837  		{
  1838  			// These are the transaction params
  1839  			UpdaterPublicKeyBase58Check:  m3Pub,
  1840  			UpdaterPrivateKeyBase58Check: m3Priv,
  1841  			ProfilePublicKeyBase58Check:  m3Pub,
  1842  			OperationType:                CreatorCoinOperationTypeSell,
  1843  			DeSoToSellNanos:              0,
  1844  			CreatorCoinToSellNanos:       4925685829,
  1845  			DeSoToAddNanos:               0,
  1846  			MinDeSoExpectedNanos:         0,
  1847  			MinCreatorCoinExpectedNanos:  0,
  1848  
  1849  			// These are the expectations
  1850  			CoinsInCirculationNanos: 3000014,
  1851  			DeSoLockedNanos:         1,
  1852  			CoinWatermarkNanos:      13613944261,
  1853  			m0CCBalance:             0,
  1854  			m0HasPurchased:          false,
  1855  			m1CCBalance:             0,
  1856  			m1HasPurchased:          false,
  1857  			m2CCBalance:             0,
  1858  			m2HasPurchased:          false,
  1859  			m3CCBalance:             3000014,
  1860  			m3HasPurchased:          false,
  1861  			m0DeSoBalance:           5999999998,
  1862  			m1DeSoBalance:           6635615128,
  1863  			m2DeSoBalance:           5243756077,
  1864  			m3DeSoBalance:           6119715431,
  1865  		},
  1866  
  1867  		{
  1868  			// Have m3 sell all of their remaining stake except for 1 CreatorCoin nano
  1869  			// This should trigger the CreatorCoinAutoSellThresholdNanos threshold leaving
  1870  			// m3 with no CreatorCoins.
  1871  			UpdaterPublicKeyBase58Check:  m3Pub,
  1872  			UpdaterPrivateKeyBase58Check: m3Priv,
  1873  			ProfilePublicKeyBase58Check:  m3Pub,
  1874  			OperationType:                CreatorCoinOperationTypeSell,
  1875  			DeSoToSellNanos:              0,
  1876  			CreatorCoinToSellNanos:       3000013,
  1877  			DeSoToAddNanos:               0,
  1878  			MinDeSoExpectedNanos:         0,
  1879  			MinCreatorCoinExpectedNanos:  0,
  1880  
  1881  			// These are the expectations
  1882  			CoinsInCirculationNanos: 0,
  1883  			DeSoLockedNanos:         0,
  1884  			CoinWatermarkNanos:      13613944261,
  1885  			m0CCBalance:             0,
  1886  			m0HasPurchased:          false,
  1887  			m1CCBalance:             0,
  1888  			m1HasPurchased:          false,
  1889  			m2CCBalance:             0,
  1890  			m2HasPurchased:          false,
  1891  			m3CCBalance:             0,
  1892  			m3HasPurchased:          false,
  1893  			m0DeSoBalance:           5999999998,
  1894  			m1DeSoBalance:           6635615128,
  1895  			m2DeSoBalance:           5243756077,
  1896  			m3DeSoBalance:           6119715429,
  1897  		},
  1898  
  1899  		// Have m1 buy a little more, m3 should receieve a founders reward
  1900  		{
  1901  			// These are the transaction params
  1902  			UpdaterPublicKeyBase58Check:  m1Pub,
  1903  			UpdaterPrivateKeyBase58Check: m1Priv,
  1904  			ProfilePublicKeyBase58Check:  m3Pub,
  1905  			OperationType:                CreatorCoinOperationTypeBuy,
  1906  			DeSoToSellNanos:              2123456789,
  1907  			CreatorCoinToSellNanos:       0,
  1908  			DeSoToAddNanos:               0,
  1909  			MinDeSoExpectedNanos:         0,
  1910  			MinCreatorCoinExpectedNanos:  0,
  1911  
  1912  			// These are the expectations
  1913  			CoinsInCirculationNanos: 12852863707,
  1914  			DeSoLockedNanos:         2123244443,
  1915  			CoinWatermarkNanos:      13613944261,
  1916  			m0CCBalance:             0,
  1917  			m0HasPurchased:          false,
  1918  			m1CCBalance:             9639647781,
  1919  			m1HasPurchased:          true,
  1920  			m2CCBalance:             0,
  1921  			m2HasPurchased:          false,
  1922  			m3CCBalance:             3213215926,
  1923  			m3HasPurchased:          false,
  1924  			m0DeSoBalance:           5999999998,
  1925  			m1DeSoBalance:           4512158337,
  1926  			m2DeSoBalance:           5243756077,
  1927  			m3DeSoBalance:           6119715429,
  1928  		},
  1929  
  1930  		// Have m1 sell their creator coins except CreatorCoinAutoSellThresholdNanos - 1. This should
  1931  		// cause an auto sell and m1 back to zero.
  1932  		{
  1933  			// These are the transaction params
  1934  			UpdaterPublicKeyBase58Check:  m1Pub,
  1935  			UpdaterPrivateKeyBase58Check: m1Priv,
  1936  			ProfilePublicKeyBase58Check:  m3Pub,
  1937  			OperationType:                CreatorCoinOperationTypeSell,
  1938  			DeSoToSellNanos:              0,
  1939  			CreatorCoinToSellNanos:       9639647781 - DeSoMainnetParams.CreatorCoinAutoSellThresholdNanos + 1,
  1940  			DeSoToAddNanos:               0,
  1941  			MinDeSoExpectedNanos:         0,
  1942  			MinCreatorCoinExpectedNanos:  0,
  1943  
  1944  			// These are the expectations
  1945  			CoinsInCirculationNanos: 3213215926,
  1946  			DeSoLockedNanos:         33175681,
  1947  			CoinWatermarkNanos:      13613944261,
  1948  			m0CCBalance:             0,
  1949  			m0HasPurchased:          false,
  1950  			m1CCBalance:             0,
  1951  			m1HasPurchased:          false,
  1952  			m2CCBalance:             0,
  1953  			m2HasPurchased:          false,
  1954  			m3CCBalance:             3213215926,
  1955  			m3HasPurchased:          false,
  1956  			m0DeSoBalance:           5999999998,
  1957  			m1DeSoBalance:           6602018090,
  1958  			m2DeSoBalance:           5243756077,
  1959  			m3DeSoBalance:           6119715429,
  1960  		},
  1961  	}
  1962  
  1963  	_helpTestCreatorCoinBuySell(t, creatorCoinTests, false)
  1964  }
  1965  
  1966  func TestSwapIdentityFailureCases(t *testing.T) {
  1967  	assert := assert.New(t)
  1968  	require := require.New(t)
  1969  	_, _ = assert, require
  1970  
  1971  	// Set up a blockchain
  1972  	chain, params, db := NewLowDifficultyBlockchain()
  1973  	mempool, miner := NewTestMiner(t, chain, params, true /*isSender*/)
  1974  	feeRateNanosPerKB := uint64(11)
  1975  	_, _ = mempool, miner
  1976  
  1977  	// Send money to people from moneyPk
  1978  	_, _, _ = _doBasicTransferWithViewFlush(
  1979  		t, chain, db, params, moneyPkString, paramUpdaterPub,
  1980  		moneyPrivString, 6*NanosPerUnit /*amount to send*/, feeRateNanosPerKB /*feerate*/)
  1981  	_, _, _ = _doBasicTransferWithViewFlush(
  1982  		t, chain, db, params, moneyPkString, m0Pub,
  1983  		moneyPrivString, 6*NanosPerUnit /*amount to send*/, feeRateNanosPerKB /*feerate*/)
  1984  	_, _, _ = _doBasicTransferWithViewFlush(
  1985  		t, chain, db, params, moneyPkString, m1Pub,
  1986  		moneyPrivString, 6*NanosPerUnit /*amount to send*/, feeRateNanosPerKB /*feerate*/)
  1987  	_, _, _ = _doBasicTransferWithViewFlush(
  1988  		t, chain, db, params, moneyPkString, m2Pub,
  1989  		moneyPrivString, 6*NanosPerUnit /*amount to send*/, feeRateNanosPerKB /*feerate*/)
  1990  
  1991  	// Create a paramUpdater for this test
  1992  	params.ParamUpdaterPublicKeys[MakePkMapKey(paramUpdaterPkBytes)] = true
  1993  
  1994  	// Swapping identities with a key that is not paramUpdater should fail.
  1995  	_, _, _, err := _swapIdentity(
  1996  		t, chain, db, params, feeRateNanosPerKB,
  1997  		m0Pub,
  1998  		m0Priv,
  1999  		m1PkBytes, m2PkBytes)
  2000  	require.Error(err)
  2001  	require.Contains(err.Error(), RuleErrorSwapIdentityIsParamUpdaterOnly)
  2002  
  2003  	// Swapping identities with a key that is not paramUpdater should fail.
  2004  	// - Case where the transactor is the from public key
  2005  	_, _, _, err = _swapIdentity(
  2006  		t, chain, db, params, feeRateNanosPerKB,
  2007  		m0Pub,
  2008  		m0Priv,
  2009  		m0PkBytes, m2PkBytes)
  2010  	require.Error(err)
  2011  	require.Contains(err.Error(), RuleErrorSwapIdentityIsParamUpdaterOnly)
  2012  
  2013  	// Swapping identities with a key that is not paramUpdater should fail.
  2014  	// - Case where the transactor is the to public key
  2015  	_, _, _, err = _swapIdentity(
  2016  		t, chain, db, params, feeRateNanosPerKB,
  2017  		m0Pub,
  2018  		m0Priv,
  2019  		m2PkBytes, m0PkBytes)
  2020  	require.Error(err)
  2021  	require.Contains(err.Error(), RuleErrorSwapIdentityIsParamUpdaterOnly)
  2022  }
  2023  
  2024  func TestSwapIdentityMain(t *testing.T) {
  2025  	// Set up a blockchain
  2026  	assert := assert.New(t)
  2027  	require := require.New(t)
  2028  	_, _ = assert, require
  2029  
  2030  	creatorCoinTests := []*_CreatorCoinTestData{
  2031  		// Create a profile for m0 so we can check creator coin balances easily.
  2032  		{
  2033  			TxnType:                      TxnTypeUpdateProfile,
  2034  			UpdaterPublicKeyBase58Check:  m0Pub,
  2035  			UpdaterPrivateKeyBase58Check: m0Priv,
  2036  			ProfilePublicKeyBase58Check:  m0Pub,
  2037  			ProfileUsername:              "m0",
  2038  			ProfileDescription:           "i am m0",
  2039  			ProfilePic:                   "m0 profile pic",
  2040  			ProfileCreatorBasisPoints:    2500,
  2041  			ProfileIsHidden:              false,
  2042  
  2043  			SkipChecks: true,
  2044  		},
  2045  		// Swap m1 and m2, which don't have profiles yet. This should work.
  2046  		{
  2047  			TxnType:       TxnTypeSwapIdentity,
  2048  			FromPublicKey: m1PkBytes,
  2049  			ToPublicKey:   m2PkBytes,
  2050  			// This is the creator whose coins we are testing the balances of.
  2051  			// Normally it's m0, but because we swapped m0 for m3 we should test
  2052  			// that one instead.
  2053  			ProfilePublicKeyBase58Check: m0Pub,
  2054  
  2055  			// These are the expectations
  2056  			CoinsInCirculationNanos: 0,
  2057  			DeSoLockedNanos:         0,
  2058  			CoinWatermarkNanos:      0,
  2059  			m0CCBalance:             0,
  2060  			m0HasPurchased:          false,
  2061  			m1CCBalance:             0,
  2062  			m1HasPurchased:          false,
  2063  			m2CCBalance:             0,
  2064  			m2HasPurchased:          false,
  2065  			m3CCBalance:             0,
  2066  			m3HasPurchased:          false,
  2067  			m4CCBalance:             0,
  2068  			m4HasPurchased:          false,
  2069  			m5CCBalance:             0,
  2070  			m5HasPurchased:          false,
  2071  			m6CCBalance:             0,
  2072  			m6HasPurchased:          false,
  2073  			m0DeSoBalance:           5999999998, // m0 lost 2 nanos in fees when creating her profile
  2074  			m1DeSoBalance:           6000000000,
  2075  			m2DeSoBalance:           6000000000,
  2076  			m3DeSoBalance:           6000000000,
  2077  			m4DeSoBalance:           6000000000,
  2078  			m5DeSoBalance:           6000000000,
  2079  			m6DeSoBalance:           6000000000,
  2080  
  2081  			// Profiles should not exist for either of these keys
  2082  			ProfilesToCheckPublicKeysBase58Check: []string{m1Pub, m2Pub},
  2083  			ProfilesToCheckUsernames:             []string{"", ""},
  2084  		},
  2085  		// Create a profile for m3
  2086  		{
  2087  			TxnType:                      TxnTypeUpdateProfile,
  2088  			UpdaterPublicKeyBase58Check:  m3Pub,
  2089  			UpdaterPrivateKeyBase58Check: m3Priv,
  2090  			ProfilePublicKeyBase58Check:  m3Pub,
  2091  			ProfileUsername:              "m3",
  2092  			ProfileDescription:           "i am m3",
  2093  			ProfilePic:                   "m3 profile pic",
  2094  			ProfileCreatorBasisPoints:    2500,
  2095  			ProfileIsHidden:              false,
  2096  
  2097  			// These are the expectations
  2098  			CoinsInCirculationNanos: 0,
  2099  			DeSoLockedNanos:         0,
  2100  			CoinWatermarkNanos:      0,
  2101  			m0CCBalance:             0,
  2102  			m0HasPurchased:          false,
  2103  			m1CCBalance:             0,
  2104  			m1HasPurchased:          false,
  2105  			m2CCBalance:             0,
  2106  			m2HasPurchased:          false,
  2107  			m3CCBalance:             0,
  2108  			m3HasPurchased:          false,
  2109  			m4CCBalance:             0,
  2110  			m4HasPurchased:          false,
  2111  			m5CCBalance:             0,
  2112  			m5HasPurchased:          false,
  2113  			m6CCBalance:             0,
  2114  			m6HasPurchased:          false,
  2115  			m0DeSoBalance:           5999999998,
  2116  			m1DeSoBalance:           6000000000,
  2117  			m2DeSoBalance:           6000000000,
  2118  			m3DeSoBalance:           5999999998,
  2119  			m4DeSoBalance:           6000000000,
  2120  			m5DeSoBalance:           6000000000,
  2121  			m6DeSoBalance:           6000000000,
  2122  
  2123  			// Profile check
  2124  			ProfilesToCheckPublicKeysBase58Check: []string{m0Pub, m3Pub},
  2125  			ProfilesToCheckUsernames:             []string{"m0", "m3"},
  2126  			ProfilesToCheckDescriptions:          []string{"i am m0", "i am m3"},
  2127  			ProfilesToCheckProfilePic:            []string{"m0 profile pic", "m3 profile pic"},
  2128  		},
  2129  		// Have m5 buy coins for m3
  2130  		{
  2131  			UpdaterPublicKeyBase58Check:  m5Pub,
  2132  			UpdaterPrivateKeyBase58Check: m5Priv,
  2133  			ProfilePublicKeyBase58Check:  m3Pub,
  2134  			OperationType:                CreatorCoinOperationTypeBuy,
  2135  			DeSoToSellNanos:              1271123456,
  2136  			CreatorCoinToSellNanos:       0,
  2137  			DeSoToAddNanos:               0,
  2138  			MinDeSoExpectedNanos:         0,
  2139  			MinCreatorCoinExpectedNanos:  0,
  2140  
  2141  			// These are the expectations
  2142  			CoinsInCirculationNanos: 10832150315,
  2143  			DeSoLockedNanos:         1270996343,
  2144  			CoinWatermarkNanos:      10832150315,
  2145  			m0CCBalance:             0,
  2146  			m0HasPurchased:          false,
  2147  			m1CCBalance:             0,
  2148  			m1HasPurchased:          false,
  2149  			m2CCBalance:             0,
  2150  			m2HasPurchased:          false,
  2151  			m3CCBalance:             2708037578,
  2152  			m3HasPurchased:          false,
  2153  			m4CCBalance:             0,
  2154  			m4HasPurchased:          false,
  2155  			m5CCBalance:             8124112737,
  2156  			m5HasPurchased:          true,
  2157  			m6CCBalance:             0,
  2158  			m6HasPurchased:          false,
  2159  			m0DeSoBalance:           5999999998,
  2160  			m1DeSoBalance:           6000000000,
  2161  			m2DeSoBalance:           6000000000,
  2162  			m3DeSoBalance:           5999999998,
  2163  			m4DeSoBalance:           6000000000,
  2164  			m5DeSoBalance:           4728876542,
  2165  			m6DeSoBalance:           6000000000,
  2166  
  2167  			// Profile check
  2168  			ProfilesToCheckPublicKeysBase58Check: []string{m0Pub, m3Pub},
  2169  			ProfilesToCheckUsernames:             []string{"m0", "m3"},
  2170  			ProfilesToCheckDescriptions:          []string{"i am m0", "i am m3"},
  2171  			ProfilesToCheckProfilePic:            []string{"m0 profile pic", "m3 profile pic"},
  2172  		},
  2173  		// Swap m2 and m3. Everything should stay the same except m2 should be the
  2174  		// creator everyone owns a piece of
  2175  		{
  2176  			TxnType:       TxnTypeSwapIdentity,
  2177  			FromPublicKey: m2PkBytes,
  2178  			ToPublicKey:   m3PkBytes,
  2179  			// This is the creator whose coins we are testing the balances of.
  2180  			// Normally it's m0, but because we swapped m0 for m3 we should test
  2181  			// that one instead.
  2182  			ProfilePublicKeyBase58Check: m2Pub,
  2183  
  2184  			CoinsInCirculationNanos: 10832150315,
  2185  			DeSoLockedNanos:         1270996343,
  2186  			CoinWatermarkNanos:      10832150315,
  2187  			m0CCBalance:             0,
  2188  			m0HasPurchased:          false,
  2189  			m1CCBalance:             0,
  2190  			m1HasPurchased:          false,
  2191  			m2CCBalance:             2708037578, // The CC balance moves from m3 to m2
  2192  			m2HasPurchased:          false,
  2193  			m3CCBalance:             0,
  2194  			m3HasPurchased:          false,
  2195  			m4CCBalance:             0,
  2196  			m4HasPurchased:          false,
  2197  			m5CCBalance:             8124112737,
  2198  			m5HasPurchased:          true,
  2199  			m6CCBalance:             0,
  2200  			m6HasPurchased:          false,
  2201  			m0DeSoBalance:           5999999998,
  2202  			m1DeSoBalance:           6000000000,
  2203  			m2DeSoBalance:           6000000000,
  2204  			m3DeSoBalance:           5999999998,
  2205  			m4DeSoBalance:           6000000000,
  2206  			m5DeSoBalance:           4728876542,
  2207  			m6DeSoBalance:           6000000000,
  2208  
  2209  			// Profile check. Note m2 is the public key that owns the profile now.
  2210  			ProfilesToCheckPublicKeysBase58Check: []string{m0Pub, m2Pub, m3Pub},
  2211  			ProfilesToCheckUsernames:             []string{"m0", "m3", ""},
  2212  			ProfilesToCheckDescriptions:          []string{"i am m0", "i am m3", ""},
  2213  			ProfilesToCheckProfilePic:            []string{"m0 profile pic", "m3 profile pic", ""},
  2214  		},
  2215  		// Create a profile for m3 again. This should work, since m3 lost its
  2216  		// profile to m2 easrlier
  2217  		{
  2218  			TxnType:                      TxnTypeUpdateProfile,
  2219  			UpdaterPublicKeyBase58Check:  m3Pub,
  2220  			UpdaterPrivateKeyBase58Check: m3Priv,
  2221  			ProfilePublicKeyBase58Check:  m3Pub,
  2222  			ProfileUsername:              "the_real_m3",
  2223  			ProfileDescription:           "i am the real m3",
  2224  			ProfilePic:                   "the real m3 profile pic",
  2225  			ProfileCreatorBasisPoints:    2500,
  2226  			ProfileIsHidden:              false,
  2227  
  2228  			// The CC balances are zero because we're checking against m3
  2229  			CoinsInCirculationNanos: 0,
  2230  			DeSoLockedNanos:         0,
  2231  			CoinWatermarkNanos:      0,
  2232  			m0CCBalance:             0,
  2233  			m0HasPurchased:          false,
  2234  			m1CCBalance:             0,
  2235  			m1HasPurchased:          false,
  2236  			m2CCBalance:             0,
  2237  			m2HasPurchased:          false,
  2238  			m3CCBalance:             0,
  2239  			m3HasPurchased:          false,
  2240  			m4CCBalance:             0,
  2241  			m4HasPurchased:          false,
  2242  			m5CCBalance:             0,
  2243  			m5HasPurchased:          false,
  2244  			m6CCBalance:             0,
  2245  			m6HasPurchased:          false,
  2246  			m0DeSoBalance:           5999999998,
  2247  			m1DeSoBalance:           6000000000,
  2248  			m2DeSoBalance:           6000000000,
  2249  			m3DeSoBalance:           5999999996,
  2250  			m4DeSoBalance:           6000000000,
  2251  			m5DeSoBalance:           4728876542,
  2252  			m6DeSoBalance:           6000000000,
  2253  
  2254  			// Profile check
  2255  			ProfilesToCheckPublicKeysBase58Check: []string{m0Pub, m2Pub, m3Pub},
  2256  			ProfilesToCheckUsernames:             []string{"m0", "m3", "the_real_m3"},
  2257  			ProfilesToCheckDescriptions:          []string{"i am m0", "i am m3", "i am the real m3"},
  2258  			ProfilesToCheckProfilePic:            []string{"m0 profile pic", "m3 profile pic", "the real m3 profile pic"},
  2259  		},
  2260  		// Have m6 buy some coins in m3
  2261  		{
  2262  			UpdaterPublicKeyBase58Check:  m6Pub,
  2263  			UpdaterPrivateKeyBase58Check: m6Priv,
  2264  			ProfilePublicKeyBase58Check:  m3Pub,
  2265  			OperationType:                CreatorCoinOperationTypeBuy,
  2266  			DeSoToSellNanos:              2000000001,
  2267  			CreatorCoinToSellNanos:       0,
  2268  			DeSoToAddNanos:               0,
  2269  			MinDeSoExpectedNanos:         0,
  2270  			MinCreatorCoinExpectedNanos:  0,
  2271  
  2272  			// The CC balances are zero because we're checking against m3
  2273  			CoinsInCirculationNanos: 12598787739,
  2274  			DeSoLockedNanos:         1999800000,
  2275  			CoinWatermarkNanos:      12598787739,
  2276  			m0CCBalance:             0,
  2277  			m0HasPurchased:          false,
  2278  			m1CCBalance:             0,
  2279  			m1HasPurchased:          false,
  2280  			m2CCBalance:             0,
  2281  			m2HasPurchased:          false,
  2282  			m3CCBalance:             3149696934, // m3 has some of its own coins as a founder reward
  2283  			m3HasPurchased:          false,
  2284  			m4CCBalance:             0,
  2285  			m4HasPurchased:          false,
  2286  			m5CCBalance:             0,
  2287  			m5HasPurchased:          false,
  2288  			m6CCBalance:             9449090805, // m6 now owns some m3
  2289  			m6HasPurchased:          true,
  2290  			m0DeSoBalance:           5999999998,
  2291  			m1DeSoBalance:           6000000000,
  2292  			m2DeSoBalance:           6000000000,
  2293  			m3DeSoBalance:           5999999996,
  2294  			m4DeSoBalance:           6000000000,
  2295  			m5DeSoBalance:           4728876542,
  2296  			m6DeSoBalance:           3999999997,
  2297  
  2298  			// Profile check
  2299  			ProfilesToCheckPublicKeysBase58Check: []string{m0Pub, m2Pub, m3Pub},
  2300  			ProfilesToCheckUsernames:             []string{"m0", "m3", "the_real_m3"},
  2301  			ProfilesToCheckDescriptions:          []string{"i am m0", "i am m3", "i am the real m3"},
  2302  			ProfilesToCheckProfilePic:            []string{"m0 profile pic", "m3 profile pic", "the real m3 profile pic"},
  2303  		},
  2304  		// Have m6 buy a tiny amount of m2.
  2305  		// This should fail the AutoSellThreshold test if you set it to 2 DeSoToSellNanos
  2306  		{
  2307  			UpdaterPublicKeyBase58Check:  m6Pub,
  2308  			UpdaterPrivateKeyBase58Check: m6Priv,
  2309  			ProfilePublicKeyBase58Check:  m2Pub,
  2310  			OperationType:                CreatorCoinOperationTypeBuy,
  2311  			DeSoToSellNanos:              10,
  2312  			CreatorCoinToSellNanos:       0,
  2313  			DeSoToAddNanos:               0,
  2314  			MinDeSoExpectedNanos:         0,
  2315  			MinCreatorCoinExpectedNanos:  0,
  2316  
  2317  			CoinsInCirculationNanos: 10832150340,
  2318  			DeSoLockedNanos:         1270996352,
  2319  			CoinWatermarkNanos:      10832150340,
  2320  			m0CCBalance:             0,
  2321  			m0HasPurchased:          false,
  2322  			m1CCBalance:             0,
  2323  			m1HasPurchased:          false,
  2324  			m2CCBalance:             2708037584, // The CC balance moves from m3 to m2
  2325  			m2HasPurchased:          false,
  2326  			m3CCBalance:             0,
  2327  			m3HasPurchased:          false,
  2328  			m4CCBalance:             0,
  2329  			m4HasPurchased:          false,
  2330  			m5CCBalance:             8124112737,
  2331  			m5HasPurchased:          true,
  2332  			m6CCBalance:             19,
  2333  			m6HasPurchased:          true,
  2334  			m0DeSoBalance:           5999999998,
  2335  			m1DeSoBalance:           6000000000,
  2336  			m2DeSoBalance:           6000000000,
  2337  			m3DeSoBalance:           5999999996,
  2338  			m4DeSoBalance:           6000000000,
  2339  			m5DeSoBalance:           4728876542,
  2340  			m6DeSoBalance:           3999999985,
  2341  
  2342  			// Profile check
  2343  			ProfilesToCheckPublicKeysBase58Check: []string{m0Pub, m2Pub, m3Pub},
  2344  			ProfilesToCheckUsernames:             []string{"m0", "m3", "the_real_m3"},
  2345  			ProfilesToCheckDescriptions:          []string{"i am m0", "i am m3", "i am the real m3"},
  2346  			ProfilesToCheckProfilePic:            []string{"m0 profile pic", "m3 profile pic", "the real m3 profile pic"},
  2347  		},
  2348  		// Swap m2 and m3 again.
  2349  		{
  2350  			TxnType:       TxnTypeSwapIdentity,
  2351  			FromPublicKey: m2PkBytes,
  2352  			ToPublicKey:   m3PkBytes,
  2353  			// This is the creator whose coins we are testing the balances of.
  2354  			// Normally it's m0, but because we swapped m0 for m3 we should test
  2355  			// that one instead.
  2356  			ProfilePublicKeyBase58Check: m2Pub,
  2357  
  2358  			CoinsInCirculationNanos: 12598787739,
  2359  			DeSoLockedNanos:         1999800000,
  2360  			CoinWatermarkNanos:      12598787739,
  2361  			// This was previously the m3 cap table, but now it's the m2 cap table.
  2362  			m0CCBalance:    0,
  2363  			m0HasPurchased: false,
  2364  			m1CCBalance:    0,
  2365  			m1HasPurchased: false,
  2366  			m2CCBalance:    3149696934,
  2367  			m2HasPurchased: false,
  2368  			m3CCBalance:    0,
  2369  			m3HasPurchased: false,
  2370  			m4CCBalance:    0,
  2371  			m4HasPurchased: false,
  2372  			m5CCBalance:    0,
  2373  			m5HasPurchased: false,
  2374  			m6CCBalance:    9449090805, // m6 now owns some m2
  2375  			m6HasPurchased: true,
  2376  			m0DeSoBalance:  5999999998,
  2377  			m1DeSoBalance:  6000000000,
  2378  			m2DeSoBalance:  6000000000,
  2379  			m3DeSoBalance:  5999999996,
  2380  			m4DeSoBalance:  6000000000,
  2381  			m5DeSoBalance:  4728876542,
  2382  			m6DeSoBalance:  3999999985,
  2383  
  2384  			// Profile check. Note m2 is the public key that owns the profile now.
  2385  			ProfilesToCheckPublicKeysBase58Check: []string{m0Pub, m3Pub, m2Pub},
  2386  			ProfilesToCheckUsernames:             []string{"m0", "m3", "the_real_m3"},
  2387  			ProfilesToCheckDescriptions:          []string{"i am m0", "i am m3", "i am the real m3"},
  2388  			ProfilesToCheckProfilePic:            []string{"m0 profile pic", "m3 profile pic", "the real m3 profile pic"},
  2389  		},
  2390  		// Have m5 buy a small amount of m3 and check the cap table
  2391  		// If you set the DeSoToSellNanos to 2, this will also fail the autosell threshold.
  2392  		{
  2393  			UpdaterPublicKeyBase58Check:  m5Pub,
  2394  			UpdaterPrivateKeyBase58Check: m5Priv,
  2395  			ProfilePublicKeyBase58Check:  m3Pub,
  2396  			OperationType:                CreatorCoinOperationTypeBuy,
  2397  			DeSoToSellNanos:              10,
  2398  			CreatorCoinToSellNanos:       0,
  2399  			DeSoToAddNanos:               0,
  2400  			MinDeSoExpectedNanos:         0,
  2401  			MinCreatorCoinExpectedNanos:  0,
  2402  
  2403  			CoinsInCirculationNanos: 10832150365,
  2404  			DeSoLockedNanos:         1270996361,
  2405  			CoinWatermarkNanos:      10832150365,
  2406  			m0CCBalance:             0,
  2407  			m0HasPurchased:          false,
  2408  			m1CCBalance:             0,
  2409  			m1HasPurchased:          false,
  2410  			m2CCBalance:             0, // The CC balance moves from m3 to m2
  2411  			m2HasPurchased:          false,
  2412  			m3CCBalance:             2708037590,
  2413  			m3HasPurchased:          false,
  2414  			m4CCBalance:             0,
  2415  			m4HasPurchased:          false,
  2416  			m5CCBalance:             8124112756,
  2417  			m5HasPurchased:          true,
  2418  			m6CCBalance:             19,
  2419  			m6HasPurchased:          true,
  2420  			m0DeSoBalance:           5999999998,
  2421  			m1DeSoBalance:           6000000000,
  2422  			m2DeSoBalance:           6000000000,
  2423  			m3DeSoBalance:           5999999996,
  2424  			m4DeSoBalance:           6000000000,
  2425  			m5DeSoBalance:           4728876530,
  2426  			m6DeSoBalance:           3999999985,
  2427  
  2428  			// Profile check
  2429  			ProfilesToCheckPublicKeysBase58Check: []string{m0Pub, m3Pub, m2Pub},
  2430  			ProfilesToCheckUsernames:             []string{"m0", "m3", "the_real_m3"},
  2431  			ProfilesToCheckDescriptions:          []string{"i am m0", "i am m3", "i am the real m3"},
  2432  			ProfilesToCheckProfilePic:            []string{"m0 profile pic", "m3 profile pic", "the real m3 profile pic"},
  2433  		},
  2434  		// Swap m3 for m4 and check the m4 cap table. It should be identical to
  2435  		// the m3 cap table from before.
  2436  		{
  2437  			TxnType:       TxnTypeSwapIdentity,
  2438  			FromPublicKey: m3PkBytes,
  2439  			ToPublicKey:   m4PkBytes,
  2440  			// This is the creator whose coins we are testing the balances of.
  2441  			// Normally it's m0, but because we swapped m0 for m3 we should test
  2442  			// that one instead.
  2443  			ProfilePublicKeyBase58Check: m4Pub,
  2444  
  2445  			CoinsInCirculationNanos: 10832150365,
  2446  			DeSoLockedNanos:         1270996361,
  2447  			CoinWatermarkNanos:      10832150365,
  2448  			m0CCBalance:             0,
  2449  			m0HasPurchased:          false,
  2450  			m1CCBalance:             0,
  2451  			m1HasPurchased:          false,
  2452  			m2CCBalance:             0,
  2453  			m2HasPurchased:          false,
  2454  			m3CCBalance:             0,
  2455  			m3HasPurchased:          false,
  2456  			m4CCBalance:             2708037590, // The m3 balance has moved to m4 now
  2457  			m4HasPurchased:          false,
  2458  			m5CCBalance:             8124112756,
  2459  			m5HasPurchased:          true,
  2460  			m6CCBalance:             19,
  2461  			m6HasPurchased:          true,
  2462  			m0DeSoBalance:           5999999998,
  2463  			m1DeSoBalance:           6000000000,
  2464  			m2DeSoBalance:           6000000000,
  2465  			m3DeSoBalance:           5999999996,
  2466  			m4DeSoBalance:           6000000000,
  2467  			m5DeSoBalance:           4728876530,
  2468  			m6DeSoBalance:           3999999985,
  2469  
  2470  			// Profile check
  2471  			ProfilesToCheckPublicKeysBase58Check: []string{m0Pub, m4Pub, m2Pub, m3Pub},
  2472  			ProfilesToCheckUsernames:             []string{"m0", "m3", "the_real_m3", ""},
  2473  			ProfilesToCheckDescriptions:          []string{"i am m0", "i am m3", "i am the real m3", ""},
  2474  			ProfilesToCheckProfilePic:            []string{"m0 profile pic", "m3 profile pic", "the real m3 profile pic", ""},
  2475  		},
  2476  		// Swap m2 for m3 and check the m3 cap table. It should be identical to
  2477  		// the m2 cap table from before.
  2478  		{
  2479  			TxnType:       TxnTypeSwapIdentity,
  2480  			FromPublicKey: m2PkBytes,
  2481  			ToPublicKey:   m3PkBytes,
  2482  			// This is the creator whose coins we are testing the balances of.
  2483  			// Normally it's m0, but because we swapped m0 for m3 we should test
  2484  			// that one instead.
  2485  			ProfilePublicKeyBase58Check: m3Pub,
  2486  
  2487  			CoinsInCirculationNanos: 12598787739,
  2488  			DeSoLockedNanos:         1999800000,
  2489  			CoinWatermarkNanos:      12598787739,
  2490  			// This was previously the m2 cap table, but now it's the m3 cap table.
  2491  			m0CCBalance:    0,
  2492  			m0HasPurchased: false,
  2493  			m1CCBalance:    0,
  2494  			m1HasPurchased: false,
  2495  			m2CCBalance:    0,
  2496  			m2HasPurchased: false,
  2497  			m3CCBalance:    3149696934,
  2498  			m3HasPurchased: false,
  2499  			m4CCBalance:    0,
  2500  			m4HasPurchased: false,
  2501  			m5CCBalance:    0,
  2502  			m6CCBalance:    9449090805,
  2503  			m6HasPurchased: true,
  2504  			m0DeSoBalance:  5999999998,
  2505  			m1DeSoBalance:  6000000000,
  2506  			m2DeSoBalance:  6000000000,
  2507  			m3DeSoBalance:  5999999996,
  2508  			m4DeSoBalance:  6000000000,
  2509  			m5DeSoBalance:  4728876530,
  2510  			m6DeSoBalance:  3999999985,
  2511  
  2512  			// Profile check
  2513  			ProfilesToCheckPublicKeysBase58Check: []string{m0Pub, m4Pub, m3Pub, m2Pub},
  2514  			ProfilesToCheckUsernames:             []string{"m0", "m3", "the_real_m3", ""},
  2515  			ProfilesToCheckDescriptions:          []string{"i am m0", "i am m3", "i am the real m3", ""},
  2516  			ProfilesToCheckProfilePic:            []string{"m0 profile pic", "m3 profile pic", "the real m3 profile pic", ""},
  2517  		},
  2518  		// Swap m4 and m3 and check the m4 cap table. It should be identical to the above.
  2519  		{
  2520  			TxnType:                     TxnTypeSwapIdentity,
  2521  			FromPublicKey:               m3PkBytes,
  2522  			ToPublicKey:                 m4PkBytes,
  2523  			ProfilePublicKeyBase58Check: m4Pub,
  2524  
  2525  			CoinsInCirculationNanos: 12598787739,
  2526  			DeSoLockedNanos:         1999800000,
  2527  			CoinWatermarkNanos:      12598787739,
  2528  			// This was previously the m2 cap table, but now it's the m3 cap table.
  2529  			m0CCBalance:    0,
  2530  			m0HasPurchased: false,
  2531  			m1CCBalance:    0,
  2532  			m1HasPurchased: false,
  2533  			m2CCBalance:    0,
  2534  			m2HasPurchased: false,
  2535  			m3CCBalance:    0,
  2536  			m3HasPurchased: false,
  2537  			m4CCBalance:    3149696934,
  2538  			m4HasPurchased: false,
  2539  			m5CCBalance:    0,
  2540  			m5HasPurchased: false,
  2541  			m6CCBalance:    9449090805,
  2542  			m6HasPurchased: true,
  2543  			m0DeSoBalance:  5999999998,
  2544  			m1DeSoBalance:  6000000000,
  2545  			m2DeSoBalance:  6000000000,
  2546  			m3DeSoBalance:  5999999996,
  2547  			m4DeSoBalance:  6000000000,
  2548  			m5DeSoBalance:  4728876530,
  2549  			m6DeSoBalance:  3999999985,
  2550  
  2551  			// Profile check
  2552  			ProfilesToCheckPublicKeysBase58Check: []string{m0Pub, m3Pub, m4Pub, m2Pub},
  2553  			ProfilesToCheckUsernames:             []string{"m0", "m3", "the_real_m3", ""},
  2554  			ProfilesToCheckDescriptions:          []string{"i am m0", "i am m3", "i am the real m3", ""},
  2555  			ProfilesToCheckProfilePic:            []string{"m0 profile pic", "m3 profile pic", "the real m3 profile pic", ""},
  2556  		},
  2557  		// Do a small m3 buy and check that the cap table lines up.
  2558  		{
  2559  			UpdaterPublicKeyBase58Check:  m5Pub,
  2560  			UpdaterPrivateKeyBase58Check: m5Priv,
  2561  			ProfilePublicKeyBase58Check:  m3Pub,
  2562  			OperationType:                CreatorCoinOperationTypeBuy,
  2563  			DeSoToSellNanos:              10,
  2564  			CreatorCoinToSellNanos:       0,
  2565  			DeSoToAddNanos:               0,
  2566  			MinDeSoExpectedNanos:         0,
  2567  			MinCreatorCoinExpectedNanos:  0,
  2568  
  2569  			CoinsInCirculationNanos: 10832150390,
  2570  			DeSoLockedNanos:         1270996370,
  2571  			CoinWatermarkNanos:      10832150390,
  2572  			m0CCBalance:             0,
  2573  			m0HasPurchased:          false,
  2574  			m1CCBalance:             0,
  2575  			m1HasPurchased:          false,
  2576  			m2CCBalance:             0,
  2577  			m2HasPurchased:          false,
  2578  			m3CCBalance:             2708037596,
  2579  			m3HasPurchased:          false,
  2580  			m4CCBalance:             0,
  2581  			m4HasPurchased:          false,
  2582  			m5CCBalance:             8124112775,
  2583  			m5HasPurchased:          true,
  2584  			m6CCBalance:             19,
  2585  			m6HasPurchased:          true,
  2586  			m0DeSoBalance:           5999999998,
  2587  			m1DeSoBalance:           6000000000,
  2588  			m2DeSoBalance:           6000000000,
  2589  			m3DeSoBalance:           5999999996,
  2590  			m4DeSoBalance:           6000000000,
  2591  			m5DeSoBalance:           4728876518,
  2592  			m6DeSoBalance:           3999999985,
  2593  
  2594  			// Profile check
  2595  			ProfilesToCheckPublicKeysBase58Check: []string{m0Pub, m3Pub, m4Pub, m2Pub},
  2596  			ProfilesToCheckUsernames:             []string{"m0", "m3", "the_real_m3", ""},
  2597  			ProfilesToCheckDescriptions:          []string{"i am m0", "i am m3", "i am the real m3", ""},
  2598  			ProfilesToCheckProfilePic:            []string{"m0 profile pic", "m3 profile pic", "the real m3 profile pic", ""},
  2599  		},
  2600  		// Create a profile for m2
  2601  		{
  2602  			TxnType:                      TxnTypeUpdateProfile,
  2603  			UpdaterPublicKeyBase58Check:  m2Pub,
  2604  			UpdaterPrivateKeyBase58Check: m2Priv,
  2605  			ProfilePublicKeyBase58Check:  m2Pub,
  2606  			ProfileUsername:              "the_new_m2",
  2607  			ProfileDescription:           "i am the new m2",
  2608  			ProfilePic:                   "the new m2 profile pic",
  2609  			ProfileCreatorBasisPoints:    2500,
  2610  			ProfileIsHidden:              false,
  2611  
  2612  			// The CC balances are zero because we're checking against m3
  2613  			CoinsInCirculationNanos: 0,
  2614  			DeSoLockedNanos:         0,
  2615  			CoinWatermarkNanos:      0,
  2616  			m0CCBalance:             0,
  2617  			m0HasPurchased:          false,
  2618  			m1CCBalance:             0,
  2619  			m1HasPurchased:          false,
  2620  			m2CCBalance:             0,
  2621  			m2HasPurchased:          false,
  2622  			m3CCBalance:             0,
  2623  			m3HasPurchased:          false,
  2624  			m4CCBalance:             0,
  2625  			m4HasPurchased:          false,
  2626  			m5CCBalance:             0,
  2627  			m5HasPurchased:          false,
  2628  			m6CCBalance:             0,
  2629  			m6HasPurchased:          false,
  2630  			m0DeSoBalance:           5999999998,
  2631  			m1DeSoBalance:           6000000000,
  2632  			m2DeSoBalance:           5999999998,
  2633  			m3DeSoBalance:           5999999996,
  2634  			m4DeSoBalance:           6000000000,
  2635  			m5DeSoBalance:           4728876518,
  2636  			m6DeSoBalance:           3999999985,
  2637  
  2638  			// Profile check
  2639  			ProfilesToCheckPublicKeysBase58Check: []string{m0Pub, m3Pub, m4Pub, m2Pub},
  2640  			ProfilesToCheckUsernames:             []string{"m0", "m3", "the_real_m3", "the_new_m2"},
  2641  			ProfilesToCheckDescriptions:          []string{"i am m0", "i am m3", "i am the real m3", "i am the new m2"},
  2642  			ProfilesToCheckProfilePic:            []string{"m0 profile pic", "m3 profile pic", "the real m3 profile pic", "the new m2 profile pic"},
  2643  		},
  2644  		// Swap m2 and m4 and verify that m4 now has the zeros
  2645  		{
  2646  			TxnType:                     TxnTypeSwapIdentity,
  2647  			FromPublicKey:               m2PkBytes,
  2648  			ToPublicKey:                 m4PkBytes,
  2649  			ProfilePublicKeyBase58Check: m4Pub,
  2650  
  2651  			CoinsInCirculationNanos: 0,
  2652  			DeSoLockedNanos:         0,
  2653  			CoinWatermarkNanos:      0,
  2654  			// This was previously the m2 cap table, but now it's the m3 cap table.
  2655  			m0CCBalance:    0,
  2656  			m0HasPurchased: false,
  2657  			m1CCBalance:    0,
  2658  			m1HasPurchased: false,
  2659  			m2CCBalance:    0,
  2660  			m2HasPurchased: false,
  2661  			m3CCBalance:    0,
  2662  			m3HasPurchased: false,
  2663  			m4CCBalance:    0,
  2664  			m4HasPurchased: false,
  2665  			m5CCBalance:    0,
  2666  			m5HasPurchased: false,
  2667  			m6CCBalance:    0,
  2668  			m6HasPurchased: false,
  2669  			m0DeSoBalance:  5999999998,
  2670  			m1DeSoBalance:  6000000000,
  2671  			m2DeSoBalance:  5999999998,
  2672  			m3DeSoBalance:  5999999996,
  2673  			m4DeSoBalance:  6000000000,
  2674  			m5DeSoBalance:  4728876518,
  2675  			m6DeSoBalance:  3999999985,
  2676  
  2677  			// Profile check
  2678  			ProfilesToCheckPublicKeysBase58Check: []string{m0Pub, m3Pub, m2Pub, m4Pub},
  2679  			ProfilesToCheckUsernames:             []string{"m0", "m3", "the_real_m3", "the_new_m2"},
  2680  			ProfilesToCheckDescriptions:          []string{"i am m0", "i am m3", "i am the real m3", "i am the new m2"},
  2681  			ProfilesToCheckProfilePic:            []string{"m0 profile pic", "m3 profile pic", "the real m3 profile pic", "the new m2 profile pic"},
  2682  		},
  2683  		// Do a small m2 buy and make sure that the m4 cap table is what we have
  2684  		// Setting DeSoToSellNanos to zero will cause an RuleErrorCreatorCoinBuyMustSatisfyAutoSellThresholdNanos
  2685  		// rule exception.
  2686  		{
  2687  			UpdaterPublicKeyBase58Check:  m5Pub,
  2688  			UpdaterPrivateKeyBase58Check: m5Priv,
  2689  			ProfilePublicKeyBase58Check:  m2Pub,
  2690  			OperationType:                CreatorCoinOperationTypeBuy,
  2691  			DeSoToSellNanos:              10,
  2692  			CreatorCoinToSellNanos:       0,
  2693  			DeSoToAddNanos:               0,
  2694  			MinDeSoExpectedNanos:         0,
  2695  			MinCreatorCoinExpectedNanos:  0,
  2696  
  2697  			CoinsInCirculationNanos: 12598787757,
  2698  			DeSoLockedNanos:         1999800009,
  2699  			CoinWatermarkNanos:      12598787757,
  2700  			m0CCBalance:             0,
  2701  			m0HasPurchased:          false,
  2702  			m1CCBalance:             0,
  2703  			m1HasPurchased:          false,
  2704  			m2CCBalance:             3149696938,
  2705  			m2HasPurchased:          false,
  2706  			m3CCBalance:             0,
  2707  			m3HasPurchased:          false,
  2708  			m4CCBalance:             0,
  2709  			m4HasPurchased:          false,
  2710  			m5CCBalance:             14,
  2711  			m5HasPurchased:          true,
  2712  			m6CCBalance:             9449090805,
  2713  			m6HasPurchased:          true,
  2714  			m0DeSoBalance:           5999999998,
  2715  			m1DeSoBalance:           6000000000,
  2716  			m2DeSoBalance:           5999999998,
  2717  			m3DeSoBalance:           5999999996,
  2718  			m4DeSoBalance:           6000000000,
  2719  			m5DeSoBalance:           4728876506,
  2720  			m6DeSoBalance:           3999999985,
  2721  
  2722  			// Profile check
  2723  			ProfilesToCheckPublicKeysBase58Check: []string{m0Pub, m3Pub, m2Pub, m4Pub},
  2724  			ProfilesToCheckUsernames:             []string{"m0", "m3", "the_real_m3", "the_new_m2"},
  2725  			ProfilesToCheckDescriptions:          []string{"i am m0", "i am m3", "i am the real m3", "i am the new m2"},
  2726  			ProfilesToCheckProfilePic:            []string{"m0 profile pic", "m3 profile pic", "the real m3 profile pic", "the new m2 profile pic"},
  2727  		},
  2728  	}
  2729  
  2730  	_helpTestCreatorCoinBuySell(t, creatorCoinTests, false)
  2731  }
  2732  
  2733  func TestSwapIdentityWithFollows(t *testing.T) {
  2734  	// Set up a blockchain
  2735  	assert := assert.New(t)
  2736  	require := require.New(t)
  2737  	_, _ = assert, require
  2738  
  2739  	creatorCoinTests := []*_CreatorCoinTestData{
  2740  		// Create a profile for m1
  2741  		{
  2742  			TxnType:                      TxnTypeUpdateProfile,
  2743  			UpdaterPublicKeyBase58Check:  m1Pub,
  2744  			UpdaterPrivateKeyBase58Check: m1Priv,
  2745  			ProfilePublicKeyBase58Check:  m1Pub,
  2746  			ProfileUsername:              "m1",
  2747  			ProfileDescription:           "i am m1",
  2748  			ProfilePic:                   "m1 profile pic",
  2749  			ProfileCreatorBasisPoints:    2500,
  2750  			ProfileIsHidden:              false,
  2751  
  2752  			SkipChecks: true,
  2753  		},
  2754  		// Have m0 follow m1
  2755  		{
  2756  			TxnType:                      TxnTypeFollow,
  2757  			UpdaterPublicKeyBase58Check:  m0Pub,
  2758  			UpdaterPrivateKeyBase58Check: m0Priv,
  2759  			FollowedPublicKey:            m1PkBytes,
  2760  			IsUnfollow:                   false,
  2761  			ProfilePublicKeyBase58Check:  m1Pub,
  2762  
  2763  			// Profile checks
  2764  			ProfilesToCheckPublicKeysBase58Check: []string{m1Pub, m0Pub},
  2765  			ProfilesToCheckUsernames:             []string{"m1", ""},
  2766  			ProfilesToCheckDescriptions:          []string{"i am m1", ""},
  2767  			ProfilesToCheckProfilePic:            []string{"m1 profile pic", ""},
  2768  
  2769  			// These are our follow checks
  2770  			FollowPublicKeysToCheck: []string{m0Pub, m1Pub},
  2771  			FollowPublicKeysUserIsFollowing: []map[string]bool{
  2772  				{m1Pub: true},
  2773  				{},
  2774  			},
  2775  			FollowPublicKeysFollowingThisUser: []map[string]bool{
  2776  				{},
  2777  				{m0Pub: true},
  2778  			},
  2779  		},
  2780  		// Swap m0 and m1
  2781  		{
  2782  			TxnType:                     TxnTypeSwapIdentity,
  2783  			FromPublicKey:               m0PkBytes,
  2784  			ToPublicKey:                 m1PkBytes,
  2785  			ProfilePublicKeyBase58Check: m0Pub,
  2786  
  2787  			// Profile checks
  2788  			ProfilesToCheckPublicKeysBase58Check: []string{m0Pub, m1Pub},
  2789  			ProfilesToCheckUsernames:             []string{"m1", ""},
  2790  			ProfilesToCheckDescriptions:          []string{"i am m1", ""},
  2791  			ProfilesToCheckProfilePic:            []string{"m1 profile pic", ""},
  2792  
  2793  			// Follow checks
  2794  			// The whole thing should be reversed now. Instead of m1 following
  2795  			// m0, it should be m0 following m1.
  2796  			FollowPublicKeysToCheck: []string{m0Pub, m1Pub},
  2797  			FollowPublicKeysUserIsFollowing: []map[string]bool{
  2798  				{},
  2799  				{m0Pub: true},
  2800  			},
  2801  			FollowPublicKeysFollowingThisUser: []map[string]bool{
  2802  				{m1Pub: true},
  2803  				{},
  2804  			},
  2805  		},
  2806  		// Swap m1 and m2. m2 should now be the one following m0
  2807  		{
  2808  			TxnType:                     TxnTypeSwapIdentity,
  2809  			FromPublicKey:               m1PkBytes,
  2810  			ToPublicKey:                 m2PkBytes,
  2811  			ProfilePublicKeyBase58Check: m0Pub,
  2812  
  2813  			// Profile checks
  2814  			ProfilesToCheckPublicKeysBase58Check: []string{m0Pub, m1Pub, m2Pub},
  2815  			ProfilesToCheckUsernames:             []string{"m1", "", ""},
  2816  			ProfilesToCheckDescriptions:          []string{"i am m1", "", ""},
  2817  			ProfilesToCheckProfilePic:            []string{"m1 profile pic", "", ""},
  2818  
  2819  			// Follow checks
  2820  			// The whole thing should be reversed now. Instead of m1 following
  2821  			// m0, it should be m0 following m1.
  2822  			FollowPublicKeysToCheck: []string{m0Pub, m1Pub, m2Pub},
  2823  			FollowPublicKeysUserIsFollowing: []map[string]bool{
  2824  				{},
  2825  				{},
  2826  				{m0Pub: true},
  2827  			},
  2828  			FollowPublicKeysFollowingThisUser: []map[string]bool{
  2829  				{m2Pub: true},
  2830  				{},
  2831  				{},
  2832  			},
  2833  		},
  2834  		// Give m1 a new profile
  2835  		{
  2836  			TxnType:                      TxnTypeUpdateProfile,
  2837  			UpdaterPublicKeyBase58Check:  m1Pub,
  2838  			UpdaterPrivateKeyBase58Check: m1Priv,
  2839  			ProfilePublicKeyBase58Check:  m1Pub,
  2840  			ProfileUsername:              "new_m1",
  2841  			ProfileDescription:           "i am new m1",
  2842  			ProfilePic:                   "new m1 profile pic",
  2843  			ProfileCreatorBasisPoints:    2500,
  2844  			ProfileIsHidden:              false,
  2845  
  2846  			// Profile checks
  2847  			ProfilesToCheckPublicKeysBase58Check: []string{m0Pub, m1Pub, m2Pub},
  2848  			ProfilesToCheckUsernames:             []string{"m1", "new_m1", ""},
  2849  			ProfilesToCheckDescriptions:          []string{"i am m1", "i am new m1", ""},
  2850  			ProfilesToCheckProfilePic:            []string{"m1 profile pic", "new m1 profile pic", ""},
  2851  		},
  2852  		// Have m2 follow m1
  2853  		{
  2854  			TxnType:                      TxnTypeFollow,
  2855  			UpdaterPublicKeyBase58Check:  m2Pub,
  2856  			UpdaterPrivateKeyBase58Check: m2Priv,
  2857  			FollowedPublicKey:            m1PkBytes,
  2858  			IsUnfollow:                   false,
  2859  			ProfilePublicKeyBase58Check:  m1Pub,
  2860  
  2861  			// Profile checks
  2862  			ProfilesToCheckPublicKeysBase58Check: []string{m0Pub, m1Pub, m2Pub},
  2863  			ProfilesToCheckUsernames:             []string{"m1", "new_m1", ""},
  2864  			ProfilesToCheckDescriptions:          []string{"i am m1", "i am new m1", ""},
  2865  			ProfilesToCheckProfilePic:            []string{"m1 profile pic", "new m1 profile pic", ""},
  2866  
  2867  			// Follow checks
  2868  			// The whole thing should be reversed now. Instead of m1 following
  2869  			// m0, it should be m0 following m1.
  2870  			FollowPublicKeysToCheck: []string{m0Pub, m1Pub, m2Pub},
  2871  			FollowPublicKeysUserIsFollowing: []map[string]bool{
  2872  				{},
  2873  				{},
  2874  				{m0Pub: true, m1Pub: true},
  2875  			},
  2876  			FollowPublicKeysFollowingThisUser: []map[string]bool{
  2877  				{m2Pub: true},
  2878  				{m2Pub: true},
  2879  				{},
  2880  			},
  2881  		},
  2882  		// Have m0 follow m1
  2883  		{
  2884  			TxnType:                      TxnTypeFollow,
  2885  			UpdaterPublicKeyBase58Check:  m0Pub,
  2886  			UpdaterPrivateKeyBase58Check: m0Priv,
  2887  			FollowedPublicKey:            m1PkBytes,
  2888  			IsUnfollow:                   false,
  2889  			ProfilePublicKeyBase58Check:  m1Pub,
  2890  
  2891  			// Profile checks
  2892  			ProfilesToCheckPublicKeysBase58Check: []string{m0Pub, m1Pub, m2Pub},
  2893  			ProfilesToCheckUsernames:             []string{"m1", "new_m1", ""},
  2894  			ProfilesToCheckDescriptions:          []string{"i am m1", "i am new m1", ""},
  2895  			ProfilesToCheckProfilePic:            []string{"m1 profile pic", "new m1 profile pic", ""},
  2896  
  2897  			// Follow checks
  2898  			// The whole thing should be reversed now. Instead of m1 following
  2899  			// m0, it should be m0 following m1.
  2900  			FollowPublicKeysToCheck: []string{m0Pub, m1Pub, m2Pub},
  2901  			FollowPublicKeysUserIsFollowing: []map[string]bool{
  2902  				{m1Pub: true},
  2903  				{},
  2904  				{m0Pub: true, m1Pub: true},
  2905  			},
  2906  			FollowPublicKeysFollowingThisUser: []map[string]bool{
  2907  				{m2Pub: true},
  2908  				{m2Pub: true, m0Pub: true},
  2909  				{},
  2910  			},
  2911  		},
  2912  		// Have m1 follow m0
  2913  		{
  2914  			TxnType:                      TxnTypeFollow,
  2915  			UpdaterPublicKeyBase58Check:  m1Pub,
  2916  			UpdaterPrivateKeyBase58Check: m1Priv,
  2917  			FollowedPublicKey:            m0PkBytes,
  2918  			IsUnfollow:                   false,
  2919  			ProfilePublicKeyBase58Check:  m1Pub,
  2920  
  2921  			// Profile checks
  2922  			ProfilesToCheckPublicKeysBase58Check: []string{m0Pub, m1Pub, m2Pub},
  2923  			ProfilesToCheckUsernames:             []string{"m1", "new_m1", ""},
  2924  			ProfilesToCheckDescriptions:          []string{"i am m1", "i am new m1", ""},
  2925  			ProfilesToCheckProfilePic:            []string{"m1 profile pic", "new m1 profile pic", ""},
  2926  
  2927  			// Follow checks
  2928  			// The whole thing should be reversed now. Instead of m1 following
  2929  			// m0, it should be m0 following m1.
  2930  			FollowPublicKeysToCheck: []string{m0Pub, m1Pub, m2Pub},
  2931  			FollowPublicKeysUserIsFollowing: []map[string]bool{
  2932  				{m1Pub: true},
  2933  				{m0Pub: true},
  2934  				{m0Pub: true, m1Pub: true},
  2935  			},
  2936  			FollowPublicKeysFollowingThisUser: []map[string]bool{
  2937  				{m2Pub: true, m1Pub: true},
  2938  				{m2Pub: true, m0Pub: true},
  2939  				{},
  2940  			},
  2941  		},
  2942  		// Swap m1 and m2. m2 should now inherit m1's follows
  2943  		// This is a tricky one...
  2944  		{
  2945  			TxnType:                     TxnTypeSwapIdentity,
  2946  			FromPublicKey:               m1PkBytes,
  2947  			ToPublicKey:                 m2PkBytes,
  2948  			ProfilePublicKeyBase58Check: m0Pub,
  2949  
  2950  			// Profile checks
  2951  			ProfilesToCheckPublicKeysBase58Check: []string{m0Pub, m2Pub, m1Pub},
  2952  			ProfilesToCheckUsernames:             []string{"m1", "new_m1", ""},
  2953  			ProfilesToCheckDescriptions:          []string{"i am m1", "i am new m1", ""},
  2954  			ProfilesToCheckProfilePic:            []string{"m1 profile pic", "new m1 profile pic", ""},
  2955  
  2956  			// Follow checks
  2957  			// The whole thing should be reversed now. Instead of m1 following
  2958  			// m0, it should be m0 following m1.
  2959  			FollowPublicKeysToCheck: []string{m0Pub, m1Pub, m2Pub},
  2960  			FollowPublicKeysUserIsFollowing: []map[string]bool{
  2961  				{m2Pub: true},
  2962  				{m0Pub: true, m2Pub: true},
  2963  				{m0Pub: true},
  2964  			},
  2965  			FollowPublicKeysFollowingThisUser: []map[string]bool{
  2966  				{m1Pub: true, m2Pub: true},
  2967  				{},
  2968  				{m1Pub: true, m0Pub: true},
  2969  			},
  2970  		},
  2971  		// Swap m2 and m0.
  2972  		{
  2973  			TxnType:                     TxnTypeSwapIdentity,
  2974  			FromPublicKey:               m2PkBytes,
  2975  			ToPublicKey:                 m0PkBytes,
  2976  			ProfilePublicKeyBase58Check: m0Pub,
  2977  
  2978  			// Profile checks
  2979  			ProfilesToCheckPublicKeysBase58Check: []string{m2Pub, m0Pub, m1Pub},
  2980  			ProfilesToCheckUsernames:             []string{"m1", "new_m1", ""},
  2981  			ProfilesToCheckDescriptions:          []string{"i am m1", "i am new m1", ""},
  2982  			ProfilesToCheckProfilePic:            []string{"m1 profile pic", "new m1 profile pic", ""},
  2983  
  2984  			// Follow checks
  2985  			// The whole thing should be reversed now. Instead of m1 following
  2986  			// m0, it should be m0 following m1.
  2987  			FollowPublicKeysToCheck: []string{m2Pub, m1Pub, m0Pub},
  2988  			FollowPublicKeysUserIsFollowing: []map[string]bool{
  2989  				{m0Pub: true},
  2990  				{m2Pub: true, m0Pub: true},
  2991  				{m2Pub: true},
  2992  			},
  2993  			FollowPublicKeysFollowingThisUser: []map[string]bool{
  2994  				{m1Pub: true, m0Pub: true},
  2995  				{},
  2996  				{m1Pub: true, m2Pub: true},
  2997  			},
  2998  		},
  2999  	}
  3000  
  3001  	_helpTestCreatorCoinBuySell(t, creatorCoinTests, false)
  3002  }
  3003  
  3004  func TestUpdateProfileChangeBack(t *testing.T) {
  3005  	assert := assert.New(t)
  3006  	require := require.New(t)
  3007  	_ = assert
  3008  	_ = require
  3009  
  3010  	// This test fails non-deterministically so we wrap it in a loop to make it
  3011  	// not flake.
  3012  	for ii := 0; ii < 10; ii++ {
  3013  		chain, params, db := NewLowDifficultyBlockchain()
  3014  		mempool, miner := NewTestMiner(t, chain, params, true /*isSender*/)
  3015  		// Make m3 a paramUpdater for this test
  3016  		params.ParamUpdaterPublicKeys[MakePkMapKey(m3PkBytes)] = true
  3017  
  3018  		// Mine a few blocks to give the senderPkString some money.
  3019  		_, err := miner.MineAndProcessSingleBlock(0 /*threadIndex*/, mempool)
  3020  		require.NoError(err)
  3021  		_, err = miner.MineAndProcessSingleBlock(0 /*threadIndex*/, mempool)
  3022  		require.NoError(err)
  3023  		_, err = miner.MineAndProcessSingleBlock(0 /*threadIndex*/, mempool)
  3024  		require.NoError(err)
  3025  		_, err = miner.MineAndProcessSingleBlock(0 /*threadIndex*/, mempool)
  3026  		require.NoError(err)
  3027  
  3028  		_, _, _ = _doBasicTransferWithViewFlush(
  3029  			t, chain, db, params, moneyPkString, m0Pub,
  3030  			moneyPrivString, 10000 /*amount to send*/, 11 /*feerate*/)
  3031  		_, _, _ = _doBasicTransferWithViewFlush(
  3032  			t, chain, db, params, moneyPkString, m1Pub,
  3033  			moneyPrivString, 10000 /*amount to send*/, 11 /*feerate*/)
  3034  		_, _, _ = _doBasicTransferWithViewFlush(
  3035  			t, chain, db, params, moneyPkString, m2Pub,
  3036  			moneyPrivString, 10000 /*amount to send*/, 11 /*feerate*/)
  3037  		_, _, _ = _doBasicTransferWithViewFlush(
  3038  			t, chain, db, params, moneyPkString, m3Pub,
  3039  			moneyPrivString, 10000 /*amount to send*/, 11 /*feerate*/)
  3040  
  3041  		// m0 takes m0
  3042  		{
  3043  			txn, _, _, _, err := chain.CreateUpdateProfileTxn(
  3044  				m0PkBytes,
  3045  				m0PkBytes,
  3046  				"m0",
  3047  				"",
  3048  				"",
  3049  				0,
  3050  				20000,
  3051  				false,
  3052  				0,
  3053  				100,
  3054  				mempool, /*mempool*/
  3055  				[]*DeSoOutput{})
  3056  			require.NoError(err)
  3057  
  3058  			// Sign the transaction now that its inputs are set up.
  3059  			_signTxn(t, txn, m0Priv)
  3060  			require.NoError(err)
  3061  			mempoolTxsAdded, err := mempool.processTransaction(
  3062  				txn, true /*allowUnconnectedTxn*/, false /*rateLimit*/, 0, /*peerID*/
  3063  				true /*verifySignatures*/)
  3064  			require.NoError(err)
  3065  			require.Equal(1, len(mempoolTxsAdded))
  3066  		}
  3067  		{
  3068  			txn, _, _, _, err := chain.CreateUpdateProfileTxn(
  3069  				m1PkBytes,
  3070  				m1PkBytes,
  3071  				"m1",
  3072  				"",
  3073  				"",
  3074  				0,
  3075  				20000,
  3076  				false,
  3077  				0,
  3078  				100,
  3079  				mempool, /*mempool*/
  3080  				[]*DeSoOutput{})
  3081  			require.NoError(err)
  3082  
  3083  			// Sign the transaction now that its inputs are set up.
  3084  			_signTxn(t, txn, m1Priv)
  3085  			require.NoError(err)
  3086  			mempoolTxsAdded, err := mempool.processTransaction(
  3087  				txn, true /*allowUnconnectedTxn*/, false /*rateLimit*/, 0, /*peerID*/
  3088  				true /*verifySignatures*/)
  3089  			require.NoError(err)
  3090  			require.Equal(1, len(mempoolTxsAdded))
  3091  		}
  3092  		// Write to db
  3093  		block, err := miner.MineAndProcessSingleBlock(0 /*threadIndex*/, mempool)
  3094  		require.NoError(err)
  3095  		// one for the block reward, two for the new profiles
  3096  		require.Equal(1+2, len(block.Txns))
  3097  
  3098  		// m1 takes m2
  3099  		{
  3100  			txn, _, _, _, err := chain.CreateUpdateProfileTxn(
  3101  				m1PkBytes,
  3102  				m1PkBytes,
  3103  				"m2",
  3104  				"",
  3105  				"",
  3106  				0,
  3107  				20000,
  3108  				false,
  3109  				0,
  3110  				100,
  3111  				mempool, /*mempool*/
  3112  				[]*DeSoOutput{})
  3113  			require.NoError(err)
  3114  
  3115  			// Sign the transaction now that its inputs are set up.
  3116  			_signTxn(t, txn, m1Priv)
  3117  			require.NoError(err)
  3118  			mempoolTxsAdded, err := mempool.processTransaction(
  3119  				txn, true /*allowUnconnectedTxn*/, false /*rateLimit*/, 0, /*peerID*/
  3120  				true /*verifySignatures*/)
  3121  			require.NoError(err)
  3122  			require.Equal(1, len(mempoolTxsAdded))
  3123  		}
  3124  		// m0 takes m1
  3125  		{
  3126  			txn, _, _, _, err := chain.CreateUpdateProfileTxn(
  3127  				m0PkBytes,
  3128  				m0PkBytes,
  3129  				"m1",
  3130  				"",
  3131  				"",
  3132  				0,
  3133  				20000,
  3134  				false,
  3135  				0,
  3136  				100,
  3137  				mempool, /*mempool*/
  3138  				[]*DeSoOutput{})
  3139  			require.NoError(err)
  3140  
  3141  			// Sign the transaction now that its inputs are set up.
  3142  			_signTxn(t, txn, m0Priv)
  3143  			require.NoError(err)
  3144  
  3145  			// This ensure that the read-only version of the utxoView accurately reflects the current set of profile names taken.
  3146  			utxoViewCopy, err := mempool.universalUtxoView.CopyUtxoView()
  3147  			require.NoError(err)
  3148  			txnSize := getTxnSize(*txn)
  3149  			_, _, _, _, err = utxoViewCopy.ConnectTransaction(txn, txn.Hash(), txnSize, chain.blockTip().Height+1, false, false)
  3150  			require.NoError(err)
  3151  
  3152  			mempoolTxsAdded, err := mempool.processTransaction(
  3153  				txn, true /*allowUnconnectedTxn*/, false /*rateLimit*/, 0, /*peerID*/
  3154  				true /*verifySignatures*/)
  3155  			require.NoError(err)
  3156  			require.Equal(1, len(mempoolTxsAdded))
  3157  		}
  3158  		// m1 takes m0
  3159  		{
  3160  			txn, _, _, _, err := chain.CreateUpdateProfileTxn(
  3161  				m1PkBytes,
  3162  				m1PkBytes,
  3163  				"m0",
  3164  				"",
  3165  				"",
  3166  				0,
  3167  				20000,
  3168  				false,
  3169  				0,
  3170  				100,
  3171  				mempool, /*mempool*/
  3172  				[]*DeSoOutput{})
  3173  			require.NoError(err)
  3174  
  3175  			// Sign the transaction now that its inputs are set up.
  3176  			_signTxn(t, txn, m1Priv)
  3177  			require.NoError(err)
  3178  			mempoolTxsAdded, err := mempool.processTransaction(
  3179  				txn, true /*allowUnconnectedTxn*/, false /*rateLimit*/, 0, /*peerID*/
  3180  				true /*verifySignatures*/)
  3181  			require.NoError(err)
  3182  			require.Equal(1, len(mempoolTxsAdded))
  3183  		}
  3184  		// Write to db
  3185  		block, err = miner.MineAndProcessSingleBlock(0 /*threadIndex*/, mempool)
  3186  		require.NoError(err)
  3187  		// one for the block reward, three for the new txns
  3188  		require.Equal(1+3, len(block.Txns))
  3189  
  3190  		// m2 takes m0 should fail
  3191  		{
  3192  			txn, _, _, _, err := chain.CreateUpdateProfileTxn(
  3193  				m2PkBytes,
  3194  				m2PkBytes,
  3195  				"m0",
  3196  				"",
  3197  				"",
  3198  				0,
  3199  				20000,
  3200  				false,
  3201  				0,
  3202  				100,
  3203  				mempool, /*mempool*/
  3204  				[]*DeSoOutput{})
  3205  			require.NoError(err)
  3206  
  3207  			// Sign the transaction now that its inputs are set up.
  3208  			_signTxn(t, txn, m2Priv)
  3209  			require.NoError(err)
  3210  			mempoolTxsAdded, err := mempool.processTransaction(
  3211  				txn, true /*allowUnconnectedTxn*/, false /*rateLimit*/, 0, /*peerID*/
  3212  				true /*verifySignatures*/)
  3213  			require.Error(err)
  3214  			require.Equal(0, len(mempoolTxsAdded))
  3215  		}
  3216  		// m3 takes m0 should fail
  3217  		{
  3218  			txn, _, _, _, err := chain.CreateUpdateProfileTxn(
  3219  				m3PkBytes,
  3220  				m3PkBytes,
  3221  				"m0",
  3222  				"",
  3223  				"",
  3224  				0,
  3225  				20000,
  3226  				false,
  3227  				0,
  3228  				100,
  3229  				mempool, /*mempool*/
  3230  				[]*DeSoOutput{})
  3231  			require.NoError(err)
  3232  
  3233  			// Sign the transaction now that its inputs are set up.
  3234  			_signTxn(t, txn, m3Priv)
  3235  			require.NoError(err)
  3236  			mempoolTxsAdded, err := mempool.processTransaction(
  3237  				txn, true /*allowUnconnectedTxn*/, false /*rateLimit*/, 0, /*peerID*/
  3238  				true /*verifySignatures*/)
  3239  			require.Error(err)
  3240  			require.Equal(0, len(mempoolTxsAdded))
  3241  		}
  3242  	}
  3243  }
  3244  
  3245  func TestAuthorizeDerivedKeyBasic(t *testing.T) {
  3246  	NFTTransferOrBurnAndDerivedKeysBlockHeight = uint32(0)
  3247  
  3248  	assert := assert.New(t)
  3249  	require := require.New(t)
  3250  	_ = assert
  3251  	_ = require
  3252  
  3253  	chain, params, db := NewLowDifficultyBlockchain()
  3254  	mempool, miner := NewTestMiner(t, chain, params, true /*isSender*/)
  3255  
  3256  	// Mine two blocks to give the sender some DeSo.
  3257  	_, err := miner.MineAndProcessSingleBlock(0 /*threadIndex*/, mempool)
  3258  	require.NoError(err)
  3259  	_, err = miner.MineAndProcessSingleBlock(0 /*threadIndex*/, mempool)
  3260  	require.NoError(err)
  3261  
  3262  	senderPkBytes, _, err := Base58CheckDecode(senderPkString)
  3263  	require.NoError(err)
  3264  	senderPrivBytes, _, err := Base58CheckDecode(senderPrivString)
  3265  	require.NoError(err)
  3266  	recipientPkBytes, _, err := Base58CheckDecode(recipientPkString)
  3267  	require.NoError(err)
  3268  
  3269  	// Get AuthorizeDerivedKey txn metadata with expiration at block 6
  3270  	senderPriv, _ := btcec.PrivKeyFromBytes(btcec.S256(), senderPrivBytes)
  3271  	authTxnMeta, derivedPriv := _getAuthorizeDerivedKeyMetadata(t, senderPriv, params, 6, false)
  3272  	derivedPrivBase58Check := Base58CheckEncode(derivedPriv.Serialize(), true, params)
  3273  	derivedPkBytes := derivedPriv.PubKey().SerializeCompressed()
  3274  	fmt.Println("Derived public key:", hex.EncodeToString(derivedPkBytes))
  3275  
  3276  	// We create this inline function for attempting a basic transfer.
  3277  	// This helps us test that the DeSoChain recognizes a derived key.
  3278  	_basicTransfer := func(senderPk []byte, recipientPk []byte, signerPriv string, utxoView *UtxoView,
  3279  		mempool *DeSoMempool, isSignerSender bool) ([]*UtxoOperation, *MsgDeSoTxn, error) {
  3280  
  3281  		txn := &MsgDeSoTxn{
  3282  			// The inputs will be set below.
  3283  			TxInputs: []*DeSoInput{},
  3284  			TxOutputs: []*DeSoOutput{
  3285  				{
  3286  					PublicKey:   recipientPk,
  3287  					AmountNanos: 1,
  3288  				},
  3289  			},
  3290  			PublicKey: senderPk,
  3291  			TxnMeta:   &BasicTransferMetadata{},
  3292  			ExtraData: make(map[string][]byte),
  3293  		}
  3294  
  3295  		totalInput, spendAmount, changeAmount, fees, err :=
  3296  			chain.AddInputsAndChangeToTransaction(txn, 10, mempool)
  3297  		require.NoError(err)
  3298  		require.Equal(totalInput, spendAmount+changeAmount+fees)
  3299  		require.Greater(totalInput, uint64(0))
  3300  
  3301  		if isSignerSender {
  3302  			// Sign the transaction with the provided derived key
  3303  			_signTxn(t, txn, signerPriv)
  3304  		} else {
  3305  			// Sign the transaction with the provided derived key
  3306  			_signTxnWithDerivedKey(t, txn, signerPriv)
  3307  		}
  3308  
  3309  		// Get utxoView if it doesn't exist
  3310  		if mempool != nil {
  3311  			utxoView, err = mempool.GetAugmentedUniversalView()
  3312  			require.NoError(err)
  3313  		}
  3314  		if utxoView == nil {
  3315  			utxoView, err = NewUtxoView(db, params, nil)
  3316  			require.NoError(err)
  3317  		}
  3318  
  3319  		txHash := txn.Hash()
  3320  		blockHeight := chain.blockTip().Height + 1
  3321  		utxoOps, _, _, _, err :=
  3322  			utxoView.ConnectTransaction(txn, txHash, getTxnSize(*txn), blockHeight,
  3323  				true /*verifySignature*/, false /*ignoreUtxos*/)
  3324  		return utxoOps, txn, err
  3325  	}
  3326  
  3327  	// Verify that the balance and expiration block in the db match expectation.
  3328  	_verifyTest := func(derivedPublicKey []byte, expirationBlockExpected uint64,
  3329  		balanceExpected uint64, operationTypeExpected AuthorizeDerivedKeyOperationType, mempool *DeSoMempool) {
  3330  		// Verify that expiration block was persisted in the db or is in mempool utxoView
  3331  		if mempool == nil {
  3332  			derivedKeyEntry := DBGetOwnerToDerivedKeyMapping(db, *NewPublicKey(senderPkBytes), *NewPublicKey(derivedPublicKey))
  3333  			// If we removed the derivedKeyEntry from utxoView altogether, it'll be nil.
  3334  			// To pass the tests, we initialize it to a default struct.
  3335  			if derivedKeyEntry == nil {
  3336  				derivedKeyEntry = &DerivedKeyEntry{*NewPublicKey(senderPkBytes), *NewPublicKey(derivedPublicKey), 0, AuthorizeDerivedKeyOperationValid, false}
  3337  			}
  3338  			assert.Equal(derivedKeyEntry.ExpirationBlock, expirationBlockExpected)
  3339  			assert.Equal(derivedKeyEntry.OperationType, operationTypeExpected)
  3340  		} else {
  3341  			utxoView, err := mempool.GetAugmentedUniversalView()
  3342  			require.NoError(err)
  3343  			derivedKeyEntry := utxoView._getDerivedKeyMappingForOwner(senderPkBytes, derivedPublicKey)
  3344  			// If we removed the derivedKeyEntry from utxoView altogether, it'll be nil.
  3345  			// To pass the tests, we initialize it to a default struct.
  3346  			if derivedKeyEntry == nil {
  3347  				derivedKeyEntry = &DerivedKeyEntry{*NewPublicKey(senderPkBytes), *NewPublicKey(derivedPublicKey), 0, AuthorizeDerivedKeyOperationValid, false}
  3348  			}
  3349  			assert.Equal(derivedKeyEntry.ExpirationBlock, expirationBlockExpected)
  3350  			assert.Equal(derivedKeyEntry.OperationType, operationTypeExpected)
  3351  		}
  3352  
  3353  		// Verify that the balance of recipient is equal to expected balance
  3354  		assert.Equal(_getBalance(t, chain, mempool, recipientPkString), balanceExpected)
  3355  	}
  3356  
  3357  	// We will use these to keep track of added utxo ops and txns
  3358  	testUtxoOps := [][]*UtxoOperation{}
  3359  	testTxns := []*MsgDeSoTxn{}
  3360  
  3361  	// Just for the sake of consistency, we run the _basicTransfer on unauthorized
  3362  	// derived key. It should fail since blockchain hasn't seen this key yet.
  3363  	{
  3364  		utxoView, err := NewUtxoView(db, params, nil)
  3365  		require.NoError(err)
  3366  		_, _, err = _basicTransfer(senderPkBytes, recipientPkBytes,
  3367  			derivedPrivBase58Check, utxoView, nil, false)
  3368  		require.Contains(err.Error(), RuleErrorDerivedKeyNotAuthorized)
  3369  
  3370  		_verifyTest(authTxnMeta.DerivedPublicKey, 0, 0, AuthorizeDerivedKeyOperationValid, nil)
  3371  		fmt.Println("Failed basic transfer signed with unauthorized derived key")
  3372  	}
  3373  	// Attempt sending an AuthorizeDerivedKey txn signed with an invalid private key.
  3374  	// This must fail because the txn has to be signed either by owner or derived key.
  3375  	{
  3376  		utxoView, err := NewUtxoView(db, params, nil)
  3377  		require.NoError(err)
  3378  		randomPrivateKey, err := btcec.NewPrivateKey(btcec.S256())
  3379  		require.NoError(err)
  3380  		randomPrivBase58Check := Base58CheckEncode(randomPrivateKey.Serialize(), true, params)
  3381  		_, _, _, err = _doAuthorizeTxn(
  3382  			t,
  3383  			chain,
  3384  			db,
  3385  			params,
  3386  			utxoView,
  3387  			10,
  3388  			senderPkBytes,
  3389  			authTxnMeta.DerivedPublicKey,
  3390  			randomPrivBase58Check,
  3391  			authTxnMeta.ExpirationBlock,
  3392  			authTxnMeta.AccessSignature,
  3393  			false)
  3394  		require.Contains(err.Error(), RuleErrorDerivedKeyNotAuthorized)
  3395  
  3396  		_verifyTest(authTxnMeta.DerivedPublicKey, 0, 0, AuthorizeDerivedKeyOperationValid, nil)
  3397  		fmt.Println("Failed connecting AuthorizeDerivedKey txn signed with an unauthorized private key.")
  3398  	}
  3399  	// Attempt sending an AuthorizeDerivedKey txn where access signature is signed with
  3400  	// an invalid private key. This must fail.
  3401  	{
  3402  		utxoView, err := NewUtxoView(db, params, nil)
  3403  		require.NoError(err)
  3404  		randomPrivateKey, err := btcec.NewPrivateKey(btcec.S256())
  3405  		require.NoError(err)
  3406  		expirationBlockByte := UintToBuf(authTxnMeta.ExpirationBlock)
  3407  		accessBytes := append(authTxnMeta.DerivedPublicKey, expirationBlockByte[:]...)
  3408  		accessSignatureRandom, err := randomPrivateKey.Sign(Sha256DoubleHash(accessBytes)[:])
  3409  		require.NoError(err)
  3410  		_, _, _, err = _doAuthorizeTxn(
  3411  			t,
  3412  			chain,
  3413  			db,
  3414  			params,
  3415  			utxoView,
  3416  			10,
  3417  			senderPkBytes,
  3418  			authTxnMeta.DerivedPublicKey,
  3419  			derivedPrivBase58Check,
  3420  			authTxnMeta.ExpirationBlock,
  3421  			accessSignatureRandom.Serialize(),
  3422  			false)
  3423  		require.Error(err)
  3424  
  3425  		_verifyTest(authTxnMeta.DerivedPublicKey, 0, 0, AuthorizeDerivedKeyOperationValid, nil)
  3426  		fmt.Println("Failed connecting AuthorizeDerivedKey txn signed with an invalid access signature.")
  3427  	}
  3428  	// Check basic transfer signed with still unauthorized derived key.
  3429  	// Should fail.
  3430  	{
  3431  		utxoView, err := NewUtxoView(db, params, nil)
  3432  		require.NoError(err)
  3433  		_, _, err = _basicTransfer(senderPkBytes, recipientPkBytes,
  3434  			derivedPrivBase58Check, utxoView, nil, false)
  3435  		require.Contains(err.Error(), RuleErrorDerivedKeyNotAuthorized)
  3436  
  3437  		_verifyTest(authTxnMeta.DerivedPublicKey, 0, 0, AuthorizeDerivedKeyOperationValid, nil)
  3438  		fmt.Println("Failed basic transfer signed with unauthorized derived key")
  3439  	}
  3440  	// Now attempt to send the same transaction but signed with the correct derived key.
  3441  	// This must pass. The new derived key will be flushed to the db here.
  3442  	{
  3443  		utxoView, err := NewUtxoView(db, params, nil)
  3444  		require.NoError(err)
  3445  		utxoOps, txn, _, err := _doAuthorizeTxn(
  3446  			t,
  3447  			chain,
  3448  			db,
  3449  			params,
  3450  			utxoView,
  3451  			10,
  3452  			senderPkBytes,
  3453  			authTxnMeta.DerivedPublicKey,
  3454  			derivedPrivBase58Check,
  3455  			authTxnMeta.ExpirationBlock,
  3456  			authTxnMeta.AccessSignature,
  3457  			false)
  3458  		require.NoError(err)
  3459  		require.NoError(utxoView.FlushToDb())
  3460  
  3461  		testUtxoOps = append(testUtxoOps, utxoOps)
  3462  		testTxns = append(testTxns, txn)
  3463  
  3464  		// Verify that expiration block was persisted in the db
  3465  		_verifyTest(authTxnMeta.DerivedPublicKey, authTxnMeta.ExpirationBlock, 0, AuthorizeDerivedKeyOperationValid, nil)
  3466  		fmt.Println("Passed connecting AuthorizeDerivedKey txn signed with an authorized private key. Flushed to Db.")
  3467  	}
  3468  	// Check basic transfer signed by the owner key.
  3469  	// Should succeed. Flush to db.
  3470  	{
  3471  		utxoView, err := NewUtxoView(db, params, nil)
  3472  		require.NoError(err)
  3473  		utxoOps, txn, err := _basicTransfer(senderPkBytes, recipientPkBytes,
  3474  			senderPrivString, utxoView, nil, true)
  3475  		require.NoError(err)
  3476  		require.NoError(utxoView.FlushToDb())
  3477  		testUtxoOps = append(testUtxoOps, utxoOps)
  3478  		testTxns = append(testTxns, txn)
  3479  
  3480  		_verifyTest(authTxnMeta.DerivedPublicKey, authTxnMeta.ExpirationBlock, 1, AuthorizeDerivedKeyOperationValid, nil)
  3481  		fmt.Println("Passed basic transfer signed with owner key. Flushed to Db.")
  3482  	}
  3483  	// Check basic transfer signed with now authorized derived key.
  3484  	// Should succeed. Flush to db.
  3485  	{
  3486  		utxoView, err := NewUtxoView(db, params, nil)
  3487  		require.NoError(err)
  3488  		utxoOps, txn, err := _basicTransfer(senderPkBytes, recipientPkBytes,
  3489  			derivedPrivBase58Check, utxoView, nil, false)
  3490  		require.NoError(err)
  3491  		require.NoError(utxoView.FlushToDb())
  3492  		testUtxoOps = append(testUtxoOps, utxoOps)
  3493  		testTxns = append(testTxns, txn)
  3494  
  3495  		_verifyTest(authTxnMeta.DerivedPublicKey, authTxnMeta.ExpirationBlock, 2, AuthorizeDerivedKeyOperationValid, nil)
  3496  		fmt.Println("Passed basic transfer signed with authorized derived key. Flushed to Db.")
  3497  	}
  3498  	// Check basic transfer signed with a random key.
  3499  	// Should fail. Well... theoretically, it could pass in a distant future.
  3500  	{
  3501  		// Generate a random key pair
  3502  		randomPrivateKey, err := btcec.NewPrivateKey(btcec.S256())
  3503  		require.NoError(err)
  3504  		randomPrivBase58Check := Base58CheckEncode(randomPrivateKey.Serialize(), true, params)
  3505  		utxoView, err := NewUtxoView(db, params, nil)
  3506  		require.NoError(err)
  3507  		_, _, err = _basicTransfer(senderPkBytes, recipientPkBytes,
  3508  			randomPrivBase58Check, utxoView, nil, false)
  3509  		require.Contains(err.Error(), RuleErrorDerivedKeyNotAuthorized)
  3510  
  3511  		_verifyTest(authTxnMeta.DerivedPublicKey, authTxnMeta.ExpirationBlock, 2, AuthorizeDerivedKeyOperationValid, nil)
  3512  		fmt.Println("Fail basic transfer signed with random key.")
  3513  	}
  3514  	// Try disconnecting all transactions so that key is deauthorized.
  3515  	// Should succeed.
  3516  	{
  3517  		for iterIndex := range testTxns {
  3518  			testIndex := len(testTxns) - 1 - iterIndex
  3519  			currentTxn := testTxns[testIndex]
  3520  			currentUtxoOps := testUtxoOps[testIndex]
  3521  			fmt.Println("currentTxn.String()", currentTxn.String())
  3522  
  3523  			// Disconnect the transaction
  3524  			utxoView, err := NewUtxoView(db, params, nil)
  3525  			require.NoError(err)
  3526  			blockHeight := chain.blockTip().Height + 1
  3527  			fmt.Printf("Disconnecting test index: %v\n", testIndex)
  3528  			require.NoError(utxoView.DisconnectTransaction(
  3529  				currentTxn, currentTxn.Hash(), currentUtxoOps, blockHeight))
  3530  			fmt.Printf("Disconnected test index: %v\n", testIndex)
  3531  
  3532  			require.NoErrorf(utxoView.FlushToDb(), "SimpleDisconnect: Index: %v", testIndex)
  3533  		}
  3534  
  3535  		_verifyTest(authTxnMeta.DerivedPublicKey, 0, 0, AuthorizeDerivedKeyOperationValid, nil)
  3536  		fmt.Println("Passed disconnecting all txns. Flushed to Db.")
  3537  	}
  3538  	// After disconnecting, check basic transfer signed with unauthorized derived key.
  3539  	// Should fail.
  3540  	{
  3541  		utxoView, err := NewUtxoView(db, params, nil)
  3542  		require.NoError(err)
  3543  		_, _, err = _basicTransfer(senderPkBytes, recipientPkBytes,
  3544  			derivedPrivBase58Check, utxoView, nil, false)
  3545  		require.Contains(err.Error(), RuleErrorDerivedKeyNotAuthorized)
  3546  
  3547  		_verifyTest(authTxnMeta.DerivedPublicKey, 0, 0, AuthorizeDerivedKeyOperationValid, nil)
  3548  		fmt.Println("Failed basic transfer signed with unauthorized derived key after disconnecting")
  3549  	}
  3550  	// Connect all txns to a single UtxoView flushing only at the end.
  3551  	{
  3552  		// Create a new UtxoView
  3553  		utxoView, err := NewUtxoView(db, params, nil)
  3554  		require.NoError(err)
  3555  		for testIndex, txn := range testTxns {
  3556  			fmt.Printf("Applying test index: %v\n", testIndex)
  3557  			blockHeight := chain.blockTip().Height + 1
  3558  			txnSize := getTxnSize(*txn)
  3559  			_, _, _, _, err :=
  3560  				utxoView.ConnectTransaction(
  3561  					txn, txn.Hash(), txnSize, blockHeight, true /*verifySignature*/, false /*ignoreUtxos*/)
  3562  			require.NoError(err)
  3563  		}
  3564  
  3565  		// Now flush at the end.
  3566  		require.NoError(utxoView.FlushToDb())
  3567  
  3568  		// Verify that expiration block and balance was persisted in the db
  3569  		_verifyTest(authTxnMeta.DerivedPublicKey, authTxnMeta.ExpirationBlock, 2, AuthorizeDerivedKeyOperationValid, nil)
  3570  		fmt.Println("Passed re-connecting all txn to a single utxoView")
  3571  	}
  3572  	// Check basic transfer signed with a random key.
  3573  	// Should fail.
  3574  	{
  3575  		// Generate a random key pair
  3576  		randomPrivateKey, err := btcec.NewPrivateKey(btcec.S256())
  3577  		require.NoError(err)
  3578  		randomPrivBase58Check := Base58CheckEncode(randomPrivateKey.Serialize(), true, params)
  3579  		utxoView, err := NewUtxoView(db, params, nil)
  3580  		require.NoError(err)
  3581  		_, _, err = _basicTransfer(senderPkBytes, recipientPkBytes,
  3582  			randomPrivBase58Check, utxoView, nil, false)
  3583  		require.Contains(err.Error(), RuleErrorDerivedKeyNotAuthorized)
  3584  
  3585  		_verifyTest(authTxnMeta.DerivedPublicKey, authTxnMeta.ExpirationBlock, 2, AuthorizeDerivedKeyOperationValid, nil)
  3586  		fmt.Println("Fail basic transfer signed with random key.")
  3587  	}
  3588  	// Disconnect all txns on a single UtxoView flushing only at the end
  3589  	{
  3590  		// Create a new UtxoView
  3591  		utxoView, err := NewUtxoView(db, params, nil)
  3592  		require.NoError(err)
  3593  		for iterIndex := range testTxns {
  3594  			testIndex := len(testTxns) - 1 - iterIndex
  3595  			blockHeight := chain.blockTip().Height + 1
  3596  			fmt.Printf("Disconnecting test index: %v\n", testIndex)
  3597  			txn := testTxns[testIndex]
  3598  			require.NoError(utxoView.DisconnectTransaction(
  3599  				txn, txn.Hash(), testUtxoOps[testIndex], blockHeight))
  3600  		}
  3601  
  3602  		// Now flush at the end.
  3603  		require.NoError(utxoView.FlushToDb())
  3604  
  3605  		// Verify that expiration block and balance was persisted in the db
  3606  		_verifyTest(authTxnMeta.DerivedPublicKey, 0, 0, AuthorizeDerivedKeyOperationValid, nil)
  3607  		fmt.Println("Passed disconnecting all txn on a single utxoView")
  3608  	}
  3609  	// Connect transactions to a single mempool, should pass.
  3610  	{
  3611  		for ii, currentTxn := range testTxns {
  3612  			mempoolTxsAdded, err := mempool.processTransaction(
  3613  				currentTxn, true /*allowUnconnectedTxn*/, true /*rateLimit*/, 0, /*peerID*/
  3614  				true /*verifySignatures*/)
  3615  			require.NoErrorf(err, "mempool index %v", ii)
  3616  			require.Equal(1, len(mempoolTxsAdded))
  3617  		}
  3618  
  3619  		// This will check the expiration block and balances according to the mempool augmented utxoView.
  3620  		_verifyTest(authTxnMeta.DerivedPublicKey, authTxnMeta.ExpirationBlock, 2, AuthorizeDerivedKeyOperationValid, mempool)
  3621  		fmt.Println("Passed connecting all txn to the mempool")
  3622  	}
  3623  	// Check basic transfer signed with a random key, when passing mempool.
  3624  	// Should fail.
  3625  	{
  3626  		// Generate a random key pair
  3627  		randomPrivateKey, err := btcec.NewPrivateKey(btcec.S256())
  3628  		require.NoError(err)
  3629  		randomPrivBase58Check := Base58CheckEncode(randomPrivateKey.Serialize(), true, params)
  3630  		_, _, err = _basicTransfer(senderPkBytes, recipientPkBytes,
  3631  			randomPrivBase58Check, nil, mempool, false)
  3632  		require.Contains(err.Error(), RuleErrorDerivedKeyNotAuthorized)
  3633  
  3634  		_verifyTest(authTxnMeta.DerivedPublicKey, authTxnMeta.ExpirationBlock, 2, AuthorizeDerivedKeyOperationValid, mempool)
  3635  		fmt.Println("Fail basic transfer signed with random key with mempool.")
  3636  	}
  3637  	// Remove all the transactions from the mempool. Should pass.
  3638  	{
  3639  		for _, burnTxn := range testTxns {
  3640  			mempool.inefficientRemoveTransaction(burnTxn)
  3641  		}
  3642  		// This will check the expiration block and balances according to the mempool augmented utxoView.
  3643  		_verifyTest(authTxnMeta.DerivedPublicKey, 0, 0, AuthorizeDerivedKeyOperationValid, mempool)
  3644  		fmt.Println("Passed removing all txn from the mempool.")
  3645  	}
  3646  	// After disconnecting, check basic transfer signed with unauthorized derived key.
  3647  	// Should fail.
  3648  	{
  3649  		_, _, err = _basicTransfer(senderPkBytes, recipientPkBytes,
  3650  			derivedPrivBase58Check, nil, mempool, false)
  3651  		require.Contains(err.Error(), RuleErrorDerivedKeyNotAuthorized)
  3652  
  3653  		_verifyTest(authTxnMeta.DerivedPublicKey, 0, 0, AuthorizeDerivedKeyOperationValid, mempool)
  3654  		fmt.Println("Failed basic transfer signed with unauthorized derived key after disconnecting")
  3655  	}
  3656  	// Re-connect transactions to a single mempool, should pass.
  3657  	{
  3658  		for ii, currentTxn := range testTxns {
  3659  			mempoolTxsAdded, err := mempool.processTransaction(
  3660  				currentTxn, true /*allowUnconnectedTxn*/, true /*rateLimit*/, 0, /*peerID*/
  3661  				true /*verifySignatures*/)
  3662  			require.NoErrorf(err, "mempool index %v", ii)
  3663  			require.Equal(1, len(mempoolTxsAdded))
  3664  		}
  3665  
  3666  		// This will check the expiration block and balances according to the mempool augmented utxoView.
  3667  		_verifyTest(authTxnMeta.DerivedPublicKey, authTxnMeta.ExpirationBlock, 2, AuthorizeDerivedKeyOperationValid, mempool)
  3668  		fmt.Println("Passed connecting all txn to the mempool.")
  3669  	}
  3670  	// We will be adding some blocks so we define an array to keep track of them.
  3671  	testBlocks := []*MsgDeSoBlock{}
  3672  	// Mine a block with all the mempool transactions.
  3673  	{
  3674  		// All the txns should be in the mempool already so mining a block should put
  3675  		// all those transactions in it.
  3676  		addedBlock, err := miner.MineAndProcessSingleBlock(0 /*threadIndex*/, mempool)
  3677  		require.NoError(err)
  3678  		testBlocks = append(testBlocks, addedBlock)
  3679  	}
  3680  	// Reset testUtxoOps and testTxns so we can test more transactions
  3681  	testUtxoOps = [][]*UtxoOperation{}
  3682  	testTxns = []*MsgDeSoTxn{}
  3683  	// Check basic transfer signed by the owner key.
  3684  	// Should succeed. Flush to db.
  3685  	{
  3686  		utxoView, err := NewUtxoView(db, params, nil)
  3687  		require.NoError(err)
  3688  		utxoOps, txn, err := _basicTransfer(senderPkBytes, recipientPkBytes,
  3689  			senderPrivString, utxoView, nil, true)
  3690  		require.NoError(err)
  3691  		require.NoError(utxoView.FlushToDb())
  3692  		testUtxoOps = append(testUtxoOps, utxoOps)
  3693  		testTxns = append(testTxns, txn)
  3694  
  3695  		fmt.Println("Passed basic transfer signed with owner key. Flushed to Db.")
  3696  		_verifyTest(authTxnMeta.DerivedPublicKey, authTxnMeta.ExpirationBlock, 3, AuthorizeDerivedKeyOperationValid, nil)
  3697  	}
  3698  	// Check basic transfer signed with authorized derived key. Now the auth txn is persisted in the db.
  3699  	// Should succeed. Flush to db.
  3700  	{
  3701  		utxoView, err := NewUtxoView(db, params, nil)
  3702  		require.NoError(err)
  3703  		utxoOps, txn, err := _basicTransfer(senderPkBytes, recipientPkBytes,
  3704  			derivedPrivBase58Check, utxoView, nil, false)
  3705  		require.NoError(err)
  3706  		require.NoError(utxoView.FlushToDb())
  3707  		testUtxoOps = append(testUtxoOps, utxoOps)
  3708  		testTxns = append(testTxns, txn)
  3709  
  3710  		_verifyTest(authTxnMeta.DerivedPublicKey, authTxnMeta.ExpirationBlock, 4, AuthorizeDerivedKeyOperationValid, nil)
  3711  		fmt.Println("Passed basic transfer signed with authorized derived key. Flushed to Db.")
  3712  	}
  3713  	// Check basic transfer signed with a random key.
  3714  	// Should fail.
  3715  	{
  3716  		// Generate a random key pair
  3717  		randomPrivateKey, err := btcec.NewPrivateKey(btcec.S256())
  3718  		require.NoError(err)
  3719  		randomPrivBase58Check := Base58CheckEncode(randomPrivateKey.Serialize(), true, params)
  3720  		utxoView, err := NewUtxoView(db, params, nil)
  3721  		require.NoError(err)
  3722  		_, _, err = _basicTransfer(senderPkBytes, recipientPkBytes,
  3723  			randomPrivBase58Check, utxoView, nil, false)
  3724  		require.Contains(err.Error(), RuleErrorDerivedKeyNotAuthorized)
  3725  
  3726  		_verifyTest(authTxnMeta.DerivedPublicKey, authTxnMeta.ExpirationBlock, 4, AuthorizeDerivedKeyOperationValid, nil)
  3727  		fmt.Println("Fail basic transfer signed with random key.")
  3728  	}
  3729  	// Try disconnecting all transactions. Should succeed.
  3730  	{
  3731  		for iterIndex := range testTxns {
  3732  			testIndex := len(testTxns) - 1 - iterIndex
  3733  			currentTxn := testTxns[testIndex]
  3734  			currentUtxoOps := testUtxoOps[testIndex]
  3735  			fmt.Println("currentTxn.String()", currentTxn.String())
  3736  
  3737  			// Disconnect the transaction
  3738  			utxoView, err := NewUtxoView(db, params, nil)
  3739  			require.NoError(err)
  3740  			blockHeight := chain.blockTip().Height + 1
  3741  			fmt.Printf("Disconnecting test index: %v\n", testIndex)
  3742  			require.NoError(utxoView.DisconnectTransaction(
  3743  				currentTxn, currentTxn.Hash(), currentUtxoOps, blockHeight))
  3744  			fmt.Printf("Disconnected test index: %v\n", testIndex)
  3745  
  3746  			require.NoErrorf(utxoView.FlushToDb(), "SimpleDisconnect: Index: %v", testIndex)
  3747  		}
  3748  
  3749  		_verifyTest(authTxnMeta.DerivedPublicKey, authTxnMeta.ExpirationBlock, 2, AuthorizeDerivedKeyOperationValid, nil)
  3750  		fmt.Println("Passed disconnecting all txns. Flushed to Db.")
  3751  	}
  3752  	// Mine a few more blocks so that the authorization should expire
  3753  	{
  3754  		for i := uint64(chain.blockTip().Height); i < authTxnMeta.ExpirationBlock; i++ {
  3755  			addedBlock, err := miner.MineAndProcessSingleBlock(0 /*threadIndex*/, mempool)
  3756  			require.NoError(err)
  3757  			testBlocks = append(testBlocks, addedBlock)
  3758  		}
  3759  		fmt.Println("Added a few more blocks.")
  3760  	}
  3761  	// Check basic transfer signed by the owner key.
  3762  	// Should succeed.
  3763  	{
  3764  		utxoView, err := NewUtxoView(db, params, nil)
  3765  		require.NoError(err)
  3766  		_, _, err = _basicTransfer(senderPkBytes, recipientPkBytes,
  3767  			senderPrivString, utxoView, nil, true)
  3768  		require.NoError(err)
  3769  
  3770  		// We're not persisting in the db so balance should remain at 2.
  3771  		_verifyTest(authTxnMeta.DerivedPublicKey, authTxnMeta.ExpirationBlock, 2, AuthorizeDerivedKeyOperationValid, nil)
  3772  		fmt.Println("Passed basic transfer signed with owner key.")
  3773  	}
  3774  	// Check basic transfer signed with expired authorized derived key.
  3775  	// Should fail.
  3776  	{
  3777  		utxoView, err := NewUtxoView(db, params, nil)
  3778  		require.NoError(err)
  3779  		_, _, err = _basicTransfer(senderPkBytes, recipientPkBytes,
  3780  			derivedPrivBase58Check, utxoView, nil, false)
  3781  		require.Contains(err.Error(), RuleErrorDerivedKeyNotAuthorized)
  3782  
  3783  		_verifyTest(authTxnMeta.DerivedPublicKey, authTxnMeta.ExpirationBlock, 2, AuthorizeDerivedKeyOperationValid, nil)
  3784  		fmt.Println("Failed a txn signed with an expired derived key.")
  3785  	}
  3786  
  3787  	// Reset testUtxoOps and testTxns so we can test more transactions
  3788  	testUtxoOps = [][]*UtxoOperation{}
  3789  	testTxns = []*MsgDeSoTxn{}
  3790  	// Get another AuthorizeDerivedKey txn metadata with expiration at block 10
  3791  	// We will try to de-authorize this key with a txn before it expires.
  3792  	authTxnMetaDeAuth, derivedDeAuthPriv := _getAuthorizeDerivedKeyMetadata(t, senderPriv, params, 10, false)
  3793  	derivedPrivDeAuthBase58Check := Base58CheckEncode(derivedDeAuthPriv.Serialize(), true, params)
  3794  	derivedDeAuthPkBytes := derivedDeAuthPriv.PubKey().SerializeCompressed()
  3795  	fmt.Println("Derived public key:", hex.EncodeToString(derivedDeAuthPkBytes))
  3796  	// Send an authorize transaction signed with the correct derived key.
  3797  	// This must pass.
  3798  	{
  3799  		utxoView, err := NewUtxoView(db, params, nil)
  3800  		require.NoError(err)
  3801  		utxoOps, txn, _, err := _doAuthorizeTxn(
  3802  			t,
  3803  			chain,
  3804  			db,
  3805  			params,
  3806  			utxoView,
  3807  			10,
  3808  			senderPkBytes,
  3809  			authTxnMetaDeAuth.DerivedPublicKey,
  3810  			derivedPrivDeAuthBase58Check,
  3811  			authTxnMetaDeAuth.ExpirationBlock,
  3812  			authTxnMetaDeAuth.AccessSignature,
  3813  			false)
  3814  		require.NoError(err)
  3815  		testUtxoOps = append(testUtxoOps, utxoOps)
  3816  		testTxns = append(testTxns, txn)
  3817  
  3818  		// Verify that expiration block was persisted in the db
  3819  		_verifyTest(authTxnMetaDeAuth.DerivedPublicKey, 0, 2, AuthorizeDerivedKeyOperationValid, nil)
  3820  		fmt.Println("Passed connecting AuthorizeDerivedKey txn signed with an authorized private key.")
  3821  	}
  3822  	// Re-connect transactions to a single mempool, should pass.
  3823  	{
  3824  		for ii, currentTxn := range testTxns {
  3825  			mempoolTxsAdded, err := mempool.processTransaction(
  3826  				currentTxn, true /*allowUnconnectedTxn*/, true /*rateLimit*/, 0, /*peerID*/
  3827  				true /*verifySignatures*/)
  3828  			require.NoErrorf(err, "mempool index %v", ii)
  3829  			require.Equal(1, len(mempoolTxsAdded))
  3830  		}
  3831  
  3832  		// This will check the expiration block and balances according to the mempool augmented utxoView.
  3833  		_verifyTest(authTxnMetaDeAuth.DerivedPublicKey, authTxnMetaDeAuth.ExpirationBlock, 2, AuthorizeDerivedKeyOperationValid, mempool)
  3834  		fmt.Println("Passed connecting all txn to the mempool.")
  3835  	}
  3836  	// Mine a block so that mempool gets flushed to db
  3837  	{
  3838  		addedBlock, err := miner.MineAndProcessSingleBlock(0 /*threadIndex*/, mempool)
  3839  		require.NoError(err)
  3840  		testBlocks = append(testBlocks, addedBlock)
  3841  		fmt.Println("Added a block.")
  3842  	}
  3843  	// Reset testUtxoOps and testTxns so we can test more transactions
  3844  	testUtxoOps = [][]*UtxoOperation{}
  3845  	testTxns = []*MsgDeSoTxn{}
  3846  	// Check basic transfer signed with new authorized derived key.
  3847  	// Sanity check. Should pass. We're not flushing to the db yet.
  3848  	{
  3849  		utxoView, err := NewUtxoView(db, params, nil)
  3850  		require.NoError(err)
  3851  		utxoOps, txn, err := _basicTransfer(senderPkBytes, recipientPkBytes,
  3852  			derivedPrivDeAuthBase58Check, utxoView, nil, false)
  3853  		require.NoError(err)
  3854  		require.NoError(utxoView.FlushToDb())
  3855  		testUtxoOps = append(testUtxoOps, utxoOps)
  3856  		testTxns = append(testTxns, txn)
  3857  
  3858  		// We're persisting to the db so balance should change to 3.
  3859  		_verifyTest(authTxnMetaDeAuth.DerivedPublicKey, authTxnMetaDeAuth.ExpirationBlock, 3, AuthorizeDerivedKeyOperationValid, nil)
  3860  		fmt.Println("Passed basic transfer signed with derived key.")
  3861  	}
  3862  	// Send a de-authorize transaction signed with a derived key.
  3863  	// Doesn't matter if it's signed by the owner or not, once a isDeleted
  3864  	// txn appears, the key should be forever expired. This must pass.
  3865  	{
  3866  		utxoView, err := NewUtxoView(db, params, nil)
  3867  		require.NoError(err)
  3868  		utxoOps, txn, _, err := _doAuthorizeTxn(
  3869  			t,
  3870  			chain,
  3871  			db,
  3872  			params,
  3873  			utxoView,
  3874  			10,
  3875  			senderPkBytes,
  3876  			authTxnMetaDeAuth.DerivedPublicKey,
  3877  			derivedPrivDeAuthBase58Check,
  3878  			10,
  3879  			authTxnMetaDeAuth.AccessSignature,
  3880  			true)
  3881  		require.NoError(err)
  3882  		require.NoError(utxoView.FlushToDb())
  3883  		testUtxoOps = append(testUtxoOps, utxoOps)
  3884  		testTxns = append(testTxns, txn)
  3885  		// Verify the expiration block in the db
  3886  		_verifyTest(authTxnMetaDeAuth.DerivedPublicKey, authTxnMetaDeAuth.ExpirationBlock, 3, AuthorizeDerivedKeyOperationNotValid, nil)
  3887  		fmt.Println("Passed connecting AuthorizeDerivedKey txn with isDeleted signed with an authorized private key.")
  3888  	}
  3889  	// Check basic transfer signed with new authorized derived key.
  3890  	// Now that key has been de-authorized this must fail.
  3891  	{
  3892  		utxoView, err := NewUtxoView(db, params, nil)
  3893  		require.NoError(err)
  3894  		_, _, err = _basicTransfer(senderPkBytes, recipientPkBytes,
  3895  			derivedPrivDeAuthBase58Check, utxoView, nil, false)
  3896  		require.Contains(err.Error(), RuleErrorDerivedKeyNotAuthorized)
  3897  
  3898  		// Since this should fail, balance wouldn't change.
  3899  		_verifyTest(authTxnMetaDeAuth.DerivedPublicKey, authTxnMetaDeAuth.ExpirationBlock, 3, AuthorizeDerivedKeyOperationNotValid, nil)
  3900  		fmt.Println("Failed basic transfer signed with de-authorized derived key.")
  3901  	}
  3902  	// Sanity check basic transfer signed by the owner key.
  3903  	// Should succeed.
  3904  	{
  3905  		utxoView, err := NewUtxoView(db, params, nil)
  3906  		require.NoError(err)
  3907  		utxoOps, txn, err := _basicTransfer(senderPkBytes, recipientPkBytes,
  3908  			senderPrivString, utxoView, nil, true)
  3909  		require.NoError(err)
  3910  		require.NoError(utxoView.FlushToDb())
  3911  		testUtxoOps = append(testUtxoOps, utxoOps)
  3912  		testTxns = append(testTxns, txn)
  3913  
  3914  		// Balance should change to 4
  3915  		_verifyTest(authTxnMetaDeAuth.DerivedPublicKey, authTxnMetaDeAuth.ExpirationBlock, 4, AuthorizeDerivedKeyOperationNotValid, nil)
  3916  		fmt.Println("Passed basic transfer signed with owner key.")
  3917  	}
  3918  	// Send an authorize transaction signed with a derived key.
  3919  	// Since we've already deleted this derived key, this must fail.
  3920  	{
  3921  		utxoView, err := NewUtxoView(db, params, nil)
  3922  		require.NoError(err)
  3923  		_, _, _, err = _doAuthorizeTxn(
  3924  			t,
  3925  			chain,
  3926  			db,
  3927  			params,
  3928  			utxoView,
  3929  			10,
  3930  			senderPkBytes,
  3931  			authTxnMetaDeAuth.DerivedPublicKey,
  3932  			derivedPrivDeAuthBase58Check,
  3933  			10,
  3934  			authTxnMetaDeAuth.AccessSignature,
  3935  			false)
  3936  		require.Contains(err.Error(), RuleErrorAuthorizeDerivedKeyDeletedDerivedPublicKey)
  3937  
  3938  		_verifyTest(authTxnMetaDeAuth.DerivedPublicKey, authTxnMetaDeAuth.ExpirationBlock, 4, AuthorizeDerivedKeyOperationNotValid, nil)
  3939  		fmt.Println("Failed connecting AuthorizeDerivedKey txn with de-authorized private key.")
  3940  	}
  3941  	// Try disconnecting all transactions. Should succeed.
  3942  	{
  3943  		for iterIndex := range testTxns {
  3944  			testIndex := len(testTxns) - 1 - iterIndex
  3945  			currentTxn := testTxns[testIndex]
  3946  			currentUtxoOps := testUtxoOps[testIndex]
  3947  			fmt.Println("currentTxn.String()", currentTxn.String())
  3948  
  3949  			// Disconnect the transaction
  3950  			utxoView, err := NewUtxoView(db, params, nil)
  3951  			require.NoError(err)
  3952  			blockHeight := chain.blockTip().Height + 1
  3953  			fmt.Printf("Disconnecting test index: %v\n", testIndex)
  3954  			require.NoError(utxoView.DisconnectTransaction(
  3955  				currentTxn, currentTxn.Hash(), currentUtxoOps, blockHeight))
  3956  			fmt.Printf("Disconnected test index: %v\n", testIndex)
  3957  
  3958  			require.NoErrorf(utxoView.FlushToDb(), "SimpleDisconnect: Index: %v", testIndex)
  3959  		}
  3960  
  3961  		_verifyTest(authTxnMetaDeAuth.DerivedPublicKey, authTxnMetaDeAuth.ExpirationBlock, 2, AuthorizeDerivedKeyOperationValid, nil)
  3962  		fmt.Println("Passed disconnecting all txns. Flushed to Db.")
  3963  	}
  3964  	// Connect transactions to a single mempool, should pass.
  3965  	{
  3966  		for ii, currentTxn := range testTxns {
  3967  			mempoolTxsAdded, err := mempool.processTransaction(
  3968  				currentTxn, true /*allowUnconnectedTxn*/, true /*rateLimit*/, 0, /*peerID*/
  3969  				true /*verifySignatures*/)
  3970  			require.NoErrorf(err, "mempool index %v", ii)
  3971  			require.Equal(1, len(mempoolTxsAdded))
  3972  		}
  3973  
  3974  		// This will check the expiration block and balances according to the mempool augmented utxoView.
  3975  		_verifyTest(authTxnMetaDeAuth.DerivedPublicKey, authTxnMetaDeAuth.ExpirationBlock, 4, AuthorizeDerivedKeyOperationNotValid, mempool)
  3976  		fmt.Println("Passed connecting all txn to the mempool")
  3977  	}
  3978  	// Check adding basic transfer to mempool signed with new authorized derived key.
  3979  	// Now that key has been de-authorized this must fail.
  3980  	{
  3981  		_, _, err = _basicTransfer(senderPkBytes, recipientPkBytes,
  3982  			derivedPrivDeAuthBase58Check, nil, mempool, false)
  3983  		require.Contains(err.Error(), RuleErrorDerivedKeyNotAuthorized)
  3984  
  3985  		// Since this should fail, balance wouldn't change.
  3986  		_verifyTest(authTxnMetaDeAuth.DerivedPublicKey, authTxnMetaDeAuth.ExpirationBlock, 4, AuthorizeDerivedKeyOperationNotValid, mempool)
  3987  		fmt.Println("Failed basic transfer signed with de-authorized derived key in mempool.")
  3988  	}
  3989  	// Attempt re-authorizing a previously de-authorized derived key.
  3990  	// Since we've already deleted this derived key, this must fail.
  3991  	{
  3992  		utxoView, err := mempool.GetAugmentedUniversalView()
  3993  		require.NoError(err)
  3994  		_, _, _, err = _doAuthorizeTxn(
  3995  			t,
  3996  			chain,
  3997  			db,
  3998  			params,
  3999  			utxoView,
  4000  			10,
  4001  			senderPkBytes,
  4002  			authTxnMetaDeAuth.DerivedPublicKey,
  4003  			derivedPrivDeAuthBase58Check,
  4004  			10,
  4005  			authTxnMetaDeAuth.AccessSignature,
  4006  			false)
  4007  		require.Contains(err.Error(), RuleErrorAuthorizeDerivedKeyDeletedDerivedPublicKey)
  4008  
  4009  		_verifyTest(authTxnMetaDeAuth.DerivedPublicKey, authTxnMetaDeAuth.ExpirationBlock, 4, AuthorizeDerivedKeyOperationNotValid, mempool)
  4010  		fmt.Println("Failed connecting AuthorizeDerivedKey txn with de-authorized private key.")
  4011  	}
  4012  	// Mine a block so that mempool gets flushed to db
  4013  	{
  4014  		addedBlock, err := miner.MineAndProcessSingleBlock(0 /*threadIndex*/, mempool)
  4015  		require.NoError(err)
  4016  		testBlocks = append(testBlocks, addedBlock)
  4017  		fmt.Println("Added a block.")
  4018  	}
  4019  	// Check adding basic transfer signed with new authorized derived key.
  4020  	// Now that key has been de-authorized this must fail.
  4021  	{
  4022  		utxoView, err := NewUtxoView(db, params, nil)
  4023  		require.NoError(err)
  4024  		_, _, err = _basicTransfer(senderPkBytes, recipientPkBytes,
  4025  			derivedPrivDeAuthBase58Check, utxoView, nil, false)
  4026  		require.Contains(err.Error(), RuleErrorDerivedKeyNotAuthorized)
  4027  
  4028  		// Since this should fail, balance wouldn't change.
  4029  		_verifyTest(authTxnMetaDeAuth.DerivedPublicKey, authTxnMetaDeAuth.ExpirationBlock, 4, AuthorizeDerivedKeyOperationNotValid, nil)
  4030  		fmt.Println("Failed basic transfer signed with de-authorized derived key.")
  4031  	}
  4032  	// Attempt re-authorizing a previously de-authorized derived key.
  4033  	// Since we've already deleted this derived key, this must fail.
  4034  	{
  4035  		utxoView, err := NewUtxoView(db, params, nil)
  4036  		require.NoError(err)
  4037  		_, _, _, err = _doAuthorizeTxn(
  4038  			t,
  4039  			chain,
  4040  			db,
  4041  			params,
  4042  			utxoView,
  4043  			10,
  4044  			senderPkBytes,
  4045  			authTxnMetaDeAuth.DerivedPublicKey,
  4046  			derivedPrivDeAuthBase58Check,
  4047  			10,
  4048  			authTxnMetaDeAuth.AccessSignature,
  4049  			false)
  4050  		require.Contains(err.Error(), RuleErrorAuthorizeDerivedKeyDeletedDerivedPublicKey)
  4051  
  4052  		_verifyTest(authTxnMetaDeAuth.DerivedPublicKey, authTxnMetaDeAuth.ExpirationBlock, 4, AuthorizeDerivedKeyOperationNotValid, nil)
  4053  		fmt.Println("Failed connecting AuthorizeDerivedKey txn with de-authorized private key.")
  4054  	}
  4055  	// Sanity check basic transfer signed by the owner key.
  4056  	// Should succeed.
  4057  	{
  4058  		utxoView, err := NewUtxoView(db, params, nil)
  4059  		require.NoError(err)
  4060  		_, _, err = _basicTransfer(senderPkBytes, recipientPkBytes,
  4061  			senderPrivString, utxoView, nil, true)
  4062  		require.NoError(err)
  4063  
  4064  		// Balance should change to 4
  4065  		_verifyTest(authTxnMetaDeAuth.DerivedPublicKey, authTxnMetaDeAuth.ExpirationBlock, 4, AuthorizeDerivedKeyOperationNotValid, nil)
  4066  		fmt.Println("Passed basic transfer signed with owner key.")
  4067  	}
  4068  	// Roll back the blocks and make sure we don't hit any errors.
  4069  	disconnectSingleBlock := func(blockToDisconnect *MsgDeSoBlock, utxoView *UtxoView) {
  4070  		// Fetch the utxo operations for the block we're detaching. We need these
  4071  		// in order to be able to detach the block.
  4072  		hash, err := blockToDisconnect.Header.Hash()
  4073  		require.NoError(err)
  4074  		utxoOps, err := GetUtxoOperationsForBlock(db, hash)
  4075  		require.NoError(err)
  4076  
  4077  		// Compute the hashes for all the transactions.
  4078  		txHashes, err := ComputeTransactionHashes(blockToDisconnect.Txns)
  4079  		require.NoError(err)
  4080  		require.NoError(utxoView.DisconnectBlock(blockToDisconnect, txHashes, utxoOps))
  4081  	}
  4082  	{
  4083  		utxoView, err := NewUtxoView(db, params, nil)
  4084  		require.NoError(err)
  4085  
  4086  		for iterIndex := range testBlocks {
  4087  			testIndex := len(testBlocks) - 1 - iterIndex
  4088  			testBlock := testBlocks[testIndex]
  4089  			disconnectSingleBlock(testBlock, utxoView)
  4090  		}
  4091  
  4092  		// Flushing the view after applying and rolling back should work.
  4093  		require.NoError(utxoView.FlushToDb())
  4094  		fmt.Println("Successfully rolled back the blocks.")
  4095  	}
  4096  
  4097  	// After we rolled back the blocks, db should reset
  4098  	_verifyTest(authTxnMeta.DerivedPublicKey, 0, 0, AuthorizeDerivedKeyOperationValid, nil)
  4099  	fmt.Println("Successfuly run TestAuthorizeDerivedKeyBasic()")
  4100  }