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