@@ -909,6 +909,198 @@ func (s *SupplyCommitMachine) InsertSignedCommitTx(ctx context.Context,
909
909
})
910
910
}
911
911
912
+ // InsertSupplyCommit inserts a new, fully complete supply commitment into the
913
+ // database.
914
+ func (s * SupplyCommitMachine ) InsertSupplyCommit (ctx context.Context ,
915
+ assetSpec asset.Specifier , commit supplycommit.RootCommitment ,
916
+ leaves supplycommit.SupplyLeaves ) error {
917
+
918
+ groupKey := assetSpec .UnwrapGroupKeyToPtr ()
919
+ if groupKey == nil {
920
+ return ErrMissingGroupKey
921
+ }
922
+ groupKeyBytes := groupKey .SerializeCompressed ()
923
+
924
+ commitTx := commit .Txn
925
+ internalKey := commit .InternalKey
926
+ outputKey := commit .OutputKey
927
+ outputIndex := commit .TxOutIdx
928
+
929
+ block , err := commit .CommitmentBlock .UnwrapOrErr (
930
+ supplycommit .ErrNoBlockInfo ,
931
+ )
932
+ if err != nil {
933
+ return fmt .Errorf ("failed to unwrap commitment block: %w" , err )
934
+ }
935
+
936
+ writeTx := WriteTxOption ()
937
+ return s .db .ExecTx (ctx , writeTx , func (db SupplyCommitStore ) error {
938
+ // Next, we'll upsert the chain transaction on disk. The block
939
+ // related fields are nil as this hasn't been confirmed yet.
940
+ var txBytes bytes.Buffer
941
+ if err := commitTx .Serialize (& txBytes ); err != nil {
942
+ return fmt .Errorf ("failed to serialize commit " +
943
+ "tx: %w" , err )
944
+ }
945
+ txid := commitTx .TxHash ()
946
+ chainTxID , err := db .UpsertChainTx (ctx , UpsertChainTxParams {
947
+ Txid : txid [:],
948
+ RawTx : txBytes .Bytes (),
949
+ })
950
+ if err != nil {
951
+ return fmt .Errorf ("failed to upsert commit chain tx: " +
952
+ "%w" , err )
953
+ }
954
+
955
+ // Upsert the internal key to get its ID. We assume key family
956
+ // and index 0 for now, as this key is likely externally.
957
+ internalKeyID , err := db .UpsertInternalKey (ctx , InternalKey {
958
+ RawKey : internalKey .PubKey .SerializeCompressed (),
959
+ KeyFamily : int32 (internalKey .Family ),
960
+ KeyIndex : int32 (internalKey .Index ),
961
+ })
962
+ if err != nil {
963
+ return fmt .Errorf ("failed to upsert internal key %x: " +
964
+ "%w" , internalKey .PubKey .SerializeCompressed (),
965
+ err )
966
+ }
967
+
968
+ // Now we fetch the previous commitment that is being spent by
969
+ // this one.
970
+ var spentCommitment sql.NullInt64
971
+ err = fn .MapOptionZ (
972
+ commit .SpentCommitment , func (op wire.OutPoint ) error {
973
+ q := sqlc.QuerySupplyCommitmentByOutpointParams {
974
+ GroupKey : groupKeyBytes ,
975
+ Txid : op .Hash [:],
976
+ OutputIndex : sqlInt32 (op .Index ),
977
+ }
978
+ row , err := db .QuerySupplyCommitmentByOutpoint (
979
+ ctx , q ,
980
+ )
981
+ if err != nil {
982
+ return fmt .Errorf ("failed to query " +
983
+ "spent commitment: %w" , err )
984
+ }
985
+
986
+ spentCommitment = sqlInt64 (
987
+ row .SupplyCommitment .CommitID ,
988
+ )
989
+
990
+ return nil
991
+ },
992
+ )
993
+
994
+ // Insert the new commitment record. Chain details (block
995
+ // height, header, proof, output index) are NULL at this stage.
996
+ newCommitmentID , err := db .InsertSupplyCommitment (
997
+ //nolint:lll
998
+ ctx , sqlc.InsertSupplyCommitmentParams {
999
+ GroupKey : groupKeyBytes ,
1000
+ ChainTxnID : chainTxID ,
1001
+ InternalKeyID : internalKeyID ,
1002
+ OutputKey : outputKey .SerializeCompressed (),
1003
+ SupplyRootHash : nil ,
1004
+ SupplyRootSum : sql.NullInt64 {},
1005
+ OutputIndex : sqlInt32 (outputIndex ),
1006
+ SpentCommitment : spentCommitment ,
1007
+ },
1008
+ )
1009
+ if err != nil {
1010
+ return fmt .Errorf ("failed to insert new supply " +
1011
+ "commitment: %w" , err )
1012
+ }
1013
+
1014
+ // Update the commitment record with the calculated root hash
1015
+ // and sum.
1016
+ finalRootSupplyRoot , err := applySupplyUpdatesInternal (
1017
+ ctx , db , assetSpec , leaves .AllUpdates (),
1018
+ )
1019
+ if err != nil {
1020
+ return fmt .Errorf ("failed to apply SMT updates: " +
1021
+ "%w" , err )
1022
+ }
1023
+ finalRootHash := finalRootSupplyRoot .NodeHash ()
1024
+ finalRootSum := finalRootSupplyRoot .NodeSum ()
1025
+ err = db .UpdateSupplyCommitmentRoot (
1026
+ ctx , UpdateSupplyCommitmentRootParams {
1027
+ CommitID : newCommitmentID ,
1028
+ SupplyRootHash : finalRootHash [:],
1029
+ SupplyRootSum : sqlInt64 (int64 (finalRootSum )),
1030
+ },
1031
+ )
1032
+ if err != nil {
1033
+ return fmt .Errorf ("failed to update commitment root " +
1034
+ "hash/sum for commit %d: %w" ,
1035
+ newCommitmentID , err )
1036
+ }
1037
+
1038
+ // Next, we'll serialize the merkle proofs and block header, so
1039
+ // we can update them on disk.
1040
+ var (
1041
+ proofBuf bytes.Buffer
1042
+ headerBuf bytes.Buffer
1043
+ )
1044
+
1045
+ err = block .MerkleProof .Encode (& proofBuf )
1046
+ if err != nil {
1047
+ return fmt .Errorf ("failed to encode " +
1048
+ "merkle proof: %w" , err )
1049
+ }
1050
+ err = block .BlockHeader .Serialize (& headerBuf )
1051
+ if err != nil {
1052
+ return fmt .Errorf ("failed to " +
1053
+ "serialize block header: %w" ,
1054
+ err )
1055
+ }
1056
+ blockHeight := sqlInt32 (block .Height )
1057
+
1058
+ // With all the information serialized above, we'll now update
1059
+ // the chain proof information for this current supply commit.
1060
+ err = db .UpdateSupplyCommitmentChainDetails (
1061
+ ctx , SupplyCommitChainDetails {
1062
+ CommitID : newCommitmentID ,
1063
+ MerkleProof : proofBuf .Bytes (),
1064
+ OutputIndex : sqlInt32 (commit .TxOutIdx ),
1065
+ BlockHeader : headerBuf .Bytes (),
1066
+ ChainTxnID : chainTxID ,
1067
+ BlockHeight : blockHeight ,
1068
+ },
1069
+ )
1070
+ if err != nil {
1071
+ return fmt .Errorf ("failed to update commitment chain " +
1072
+ "details: %w" , err )
1073
+ }
1074
+
1075
+ // Also update the chain_txns record itself with the
1076
+ // confirmation details (block hash, height, index).
1077
+ var commitTxBytes bytes.Buffer
1078
+ err = commit .Txn .Serialize (& commitTxBytes )
1079
+ if err != nil {
1080
+ return fmt .Errorf ("failed to serialize commit tx for " +
1081
+ "update: %w" , err )
1082
+ }
1083
+ commitTxid := commit .Txn .TxHash ()
1084
+
1085
+ _ , err = db .UpsertChainTx (ctx , UpsertChainTxParams {
1086
+ Txid : commitTxid [:],
1087
+ RawTx : commitTxBytes .Bytes (),
1088
+ ChainFees : 0 ,
1089
+ BlockHash : lnutils .ByteSlice (
1090
+ block .BlockHeader .BlockHash (),
1091
+ ),
1092
+ BlockHeight : blockHeight ,
1093
+ TxIndex : sqlInt32 (block .TxIndex ),
1094
+ })
1095
+ if err != nil {
1096
+ return fmt .Errorf ("failed to update chain_txns " +
1097
+ "confirmation: %w" , err )
1098
+ }
1099
+
1100
+ return nil
1101
+ })
1102
+ }
1103
+
912
1104
// CommitState commits the state of the state machine to disk.
913
1105
func (s * SupplyCommitMachine ) CommitState (ctx context.Context ,
914
1106
assetSpec asset.Specifier , state supplycommit.State ) error {
0 commit comments