@@ -269,17 +269,67 @@ func handleGetBlockHeader(ctx context.Context, s *RPCServer, cmd interface{}, _
269269
270270 diff := b .Bits .CalculateDifficulty ()
271271 diffFloat , _ := diff .Float64 ()
272+
273+ // Get best block header for confirmations calculation
274+ _ , bestBlockMeta , err := s .blockchainClient .GetBestBlockHeader (ctx )
275+ if err != nil {
276+ return nil , err
277+ }
278+
279+ // Calculate median time for this block
280+ medianTime , err := calculateMedianTime (ctx , s .blockchainClient , b .Hash ())
281+ if err != nil {
282+ // If we can't calculate median time, use block time
283+ s .logger .Warnf ("Failed to calculate median time for block %s: %v, falling back to block timestamp" , b .Hash (), err )
284+ medianTime = b .Timestamp
285+ }
286+
287+ // Handle previousblockhash for genesis block
288+ previousBlockHash := b .HashPrevBlock .String ()
289+ if meta .Height == 0 {
290+ // For genesis block, return empty string instead of zeros
291+ previousBlockHash = ""
292+ }
293+
294+ // Get next block hash unless there are none
295+ nextBlock , err := s .blockchainClient .GetBlockByHeight (ctx , meta .Height + 1 )
296+ var nextBlockHash string
297+ if err == nil && nextBlock != nil {
298+ nextBlockHash = nextBlock .Hash ().String ()
299+ }
300+
301+ // Get block size
302+ blockBytes := b .Bytes ()
303+ blockSizeInt32 , err := safeconversion .IntToInt32 (len (blockBytes ))
304+ if err != nil {
305+ return nil , err
306+ }
307+
308+ // Get transaction count from the block at this height
309+ block , err := s .blockchainClient .GetBlockByHeight (ctx , meta .Height )
310+ var numTx int
311+ if err == nil && block != nil {
312+ numTx = int (block .TransactionCount )
313+ }
314+
272315 headerReply := & bsvjson.GetBlockHeaderVerboseResult {
273- Hash : b .Hash ().String (),
274- Version : versionInt32 ,
275- VersionHex : fmt .Sprintf ("%08x" , b .Version ),
276- PreviousHash : b .HashPrevBlock .String (),
277- Nonce : nonceUint64 ,
278- Time : timeInt64 ,
279- Bits : b .Bits .String (),
280- Difficulty : diffFloat ,
281- MerkleRoot : b .HashMerkleRoot .String (),
282- Height : heightInt32 ,
316+ Hash : b .Hash ().String (),
317+ Version : versionInt32 ,
318+ VersionHex : fmt .Sprintf ("%08x" , b .Version ),
319+ PreviousHash : previousBlockHash ,
320+ Nonce : nonceUint64 ,
321+ Time : timeInt64 ,
322+ Bits : b .Bits .String (),
323+ Difficulty : diffFloat ,
324+ MerkleRoot : b .HashMerkleRoot .String (),
325+ Confirmations : int64 (1 + bestBlockMeta .Height - meta .Height ),
326+ Height : heightInt32 ,
327+ Size : blockSizeInt32 ,
328+ NumTx : numTx ,
329+ MedianTime : int64 (medianTime ),
330+ ChainWork : hex .EncodeToString (meta .ChainWork ),
331+ NextHash : nextBlockHash ,
332+ Status : "active" ,
283333 }
284334
285335 // Check if this block is on the main chain
@@ -293,13 +343,6 @@ func handleGetBlockHeader(ctx context.Context, s *RPCServer, cmd interface{}, _
293343 return headerReply , nil
294344 }
295345
296- // Block is on the main chain, calculate confirmations
297- _ , bestBlockMeta , err := s .blockchainClient .GetBestBlockHeader (ctx )
298- if err != nil {
299- return nil , err
300- }
301- headerReply .Confirmations = 1 + int64 (bestBlockMeta .Height ) - int64 (meta .Height )
302-
303346 return headerReply , nil
304347 }
305348
@@ -333,6 +376,12 @@ func (s *RPCServer) blockToJSON(ctx context.Context, b *model.Block, verbosity u
333376 return nil , err
334377 }
335378
379+ // Get block metadata for this specific block to retrieve its chain work
380+ _ , blockMeta , err := s .blockchainClient .GetBlockHeader (ctx , b .Hash ())
381+ if err != nil {
382+ return nil , err
383+ }
384+
336385 // Get next block hash unless there are none.
337386 nextBlock , err := s .blockchainClient .GetBlockByHeight (ctx , b .Height + 1 )
338387 if err != nil && ! errors .Is (err , errors .ErrBlockNotFound ) {
@@ -362,12 +411,28 @@ func (s *RPCServer) blockToJSON(ctx context.Context, b *model.Block, verbosity u
362411 return nil , err
363412 }
364413
414+ // Calculate median time for this block
415+ medianTime , err := calculateMedianTime (ctx , s .blockchainClient , b .Hash ())
416+ if err != nil {
417+ // If we can't calculate median time, use block time
418+ s .logger .Warnf ("Failed to calculate median time for block %s: %v, falling back to block timestamp" , b .Hash (), err )
419+ medianTime = b .Header .Timestamp
420+ }
421+
422+ // Handle previousblockhash for genesis block
423+ previousBlockHash := b .Header .HashPrevBlock .String ()
424+ if b .Height == 0 {
425+ // For genesis block, return empty string instead of zeros
426+ previousBlockHash = ""
427+ }
428+
429+ // Create the base block reply with all required fields
365430 baseBlockReply := & bsvjson.GetBlockBaseVerboseResult {
366431 Hash : b .Hash ().String (),
367432 Version : versionInt32 ,
368433 VersionHex : fmt .Sprintf ("%08x" , b .Header .Version ),
369434 MerkleRoot : b .Header .HashMerkleRoot .String (),
370- PreviousHash : b . Header . HashPrevBlock . String () ,
435+ PreviousHash : previousBlockHash ,
371436 Nonce : b .Header .Nonce ,
372437 Time : int64 (b .Header .Timestamp ),
373438 Confirmations : 1 + int64 (bestBlockMeta .Height ) - int64 (b .Height ),
@@ -376,42 +441,19 @@ func (s *RPCServer) blockToJSON(ctx context.Context, b *model.Block, verbosity u
376441 Bits : b .Header .Bits .String (),
377442 Difficulty : diff ,
378443 NextHash : nextBlockHash ,
444+ NumTx : int (b .TransactionCount ),
445+ MedianTime : int64 (medianTime ),
446+ ChainWork : hex .EncodeToString (blockMeta .ChainWork ),
379447 }
380448
381- // TODO: we can't add the txs to the block as there could be too many.
382- // A breaking change would be to add the subtrees.
383-
384- // If verbose level does not match 0 or 1
385- // we can consider it 2 (current bitcoin core behavior)
386- if verbosity == 1 { //nolint:wsl
387- // transactions := blk.Transactions()
388- // txNames := make([]string, len(transactions))
389- // for i, tx := range transactions {
390- // txNames[i] = tx.Hash().String()
391- // }
449+ // For verbosity 1 and above, return the JSON object
450+ // Note: Tx field is intentionally kept empty for performance reasons
451+ // to avoid large response bodies with potentially millions of transactions
452+ s .logger .Debugf ("Returning block %s with empty tx array (num_tx=%d) for performance reasons" , b .Hash (), b .TransactionCount )
392453
393- // blockReply = bsvjson.GetBlockVerboseResult{
394- // GetBlockBaseVerboseResult: baseBlockReply,
395-
396- // Tx: txNames,
397- // }
398- // } else {
399- // txns := blk.Transactions()
400- // rawTxns := make([]bsvjson.TxRawResult, len(txns))
401- // for i, tx := range txns {
402- // rawTxn, err := createTxRawResult(params, tx.MsgTx(),
403- // tx.Hash().String(), blockHeader, hash.String(),
404- // blockHeight, best.Height)
405- // if err != nil {
406- // return nil, err
407- // }
408- // rawTxns[i] = *rawTxn
409- // }
410- blockReply = & bsvjson.GetBlockVerboseTxResult {
411- GetBlockBaseVerboseResult : baseBlockReply ,
412-
413- // Tx: rawTxns,
414- }
454+ blockReply = & bsvjson.GetBlockVerboseResult {
455+ GetBlockBaseVerboseResult : baseBlockReply ,
456+ Tx : []string {}, // Empty array for backward compatibility
415457 }
416458
417459 return blockReply , nil
@@ -873,15 +915,8 @@ func handleGenerate(ctx context.Context, s *RPCServer, cmd interface{}, _ <-chan
873915 return nil , err
874916 }
875917
876- err = s .blockAssemblyClient .GenerateBlocks (ctx , & blockassembly_api.GenerateBlocksRequest {Count : numblocksInt32 })
877- if err != nil {
878- return nil , & bsvjson.RPCError {
879- Code : bsvjson .ErrRPCInternal .Code ,
880- Message : errors .NewServiceError ("RPC blockassembly client" , err ).Error (),
881- }
882- }
883-
884- return nil , nil
918+ // Generate blocks and return their hashes
919+ return s .generateBlocksAndReturnHashes (ctx , numblocksInt32 , nil , nil )
885920}
886921
887922// handleGenerateToAddress implements the generatetoaddress command, which instructs the node to
@@ -950,15 +985,8 @@ func handleGenerateToAddress(ctx context.Context, s *RPCServer, cmd interface{},
950985 }
951986 }
952987
953- err = s .blockAssemblyClient .GenerateBlocks (ctx , & blockassembly_api.GenerateBlocksRequest {Count : c .NumBlocks , Address : & c .Address , MaxTries : c .MaxTries })
954- if err != nil {
955- return nil , & bsvjson.RPCError {
956- Code : bsvjson .ErrRPCInternal .Code ,
957- Message : err .Error (),
958- }
959- }
960-
961- return nil , nil
988+ // Generate blocks and return their hashes
989+ return s .generateBlocksAndReturnHashes (ctx , c .NumBlocks , & c .Address , c .MaxTries )
962990}
963991
964992// handleGetMiningCandidate implements the getminingcandidate command, which provides
@@ -1017,6 +1045,10 @@ func handleGetMiningCandidate(ctx context.Context, s *RPCServer, cmd interface{}
10171045 return nil , err
10181046 }
10191047
1048+ // Calculate difficulty from nBits
1049+ difficulty := nBits .CalculateDifficulty ()
1050+ difficultyFloat , _ := difficulty .Float64 ()
1051+
10201052 merkleProofStrings := make ([]string , len (mc .MerkleProof ))
10211053
10221054 for i , hash := range mc .MerkleProof {
@@ -1034,6 +1066,7 @@ func handleGetMiningCandidate(ctx context.Context, s *RPCServer, cmd interface{}
10341066 "num_tx" : mc .NumTxs ,
10351067 "sizeWithoutCoinbase" : mc .SizeWithoutCoinbase ,
10361068 "merkleProof" : merkleProofStrings ,
1069+ "difficulty" : difficultyFloat ,
10371070 }
10381071
10391072 if c .ProvideCoinbaseTx != nil && * c .ProvideCoinbaseTx {
@@ -1364,17 +1397,15 @@ func handleGetblockchaininfo(ctx context.Context, s *RPCServer, cmd interface{},
13641397 return map [string ]interface {}{}, errors .NewProcessingError ("error calculating median time: %v" , err )
13651398 }
13661399
1367- // Calculate verification progress based on blockchain statistics
1400+ // Calculate verification progress based on Bitcoin SV's GuessVerificationProgress function
13681401 verificationProgress , err := calculateVerificationProgress (ctx , s .blockchainClient , bestBlockMeta .Height )
13691402 if err != nil {
13701403 // If we can't calculate verification progress, default to 1.0 (assume fully synced)
13711404 verificationProgress = 1.0
13721405 }
13731406
1374- chainWorkHash , err := chainhash .NewHash (bestBlockMeta .ChainWork )
1375- if err != nil {
1376- return map [string ]interface {}{}, errors .NewProcessingError ("error creating chain work hash: %v" , err )
1377- }
1407+ // Convert chainwork bytes to little endian hex string
1408+ chainWorkHex := hex .EncodeToString (bestBlockMeta .ChainWork )
13781409
13791410 difficultyBigFloat := bestBlockHeader .Bits .CalculateDifficulty ()
13801411 difficulty , _ := difficultyBigFloat .Float64 ()
@@ -1387,7 +1418,7 @@ func handleGetblockchaininfo(ctx context.Context, s *RPCServer, cmd interface{},
13871418 "difficulty" : difficulty , // Return as float64 to match Bitcoin SV
13881419 "mediantime" : medianTime ,
13891420 "verificationprogress" : verificationProgress ,
1390- "chainwork" : chainWorkHash . String () ,
1421+ "chainwork" : chainWorkHex ,
13911422 "pruned" : false , // the minimum relay fee for non-free transactions in BSV/KB
13921423 "softforks" : []interface {}{},
13931424 }
@@ -1399,8 +1430,8 @@ func handleGetblockchaininfo(ctx context.Context, s *RPCServer, cmd interface{},
13991430 return jsonMap , nil
14001431}
14011432
1402- // calculateVerificationProgress implements Bitcoin SV's GuessVerificationProgress function.
1403- // This is a direct translation of the Bitcoin SV code from validation.cpp:
1433+ // calculateVerificationProgress follows the pattern of Bitcoin SV's GuessVerificationProgress function.
1434+ // This is a translation of the Bitcoin SV code from validation.cpp:
14041435//
14051436// double GuessVerificationProgress(const ChainTxData &data, const CBlockIndex *pindex) {
14061437// if (pindex == nullptr) return 0.0;
@@ -1606,7 +1637,12 @@ func handleGetInfo(ctx context.Context, s *RPCServer, cmd interface{}, _ <-chan
16061637 "difficulty" : difficulty , // the current target difficulty
16071638 "testnet" : s .settings .ChainCfgParams .Net == wire .TestNet , // whether or not server is using testnet
16081639 "stn" : s .settings .ChainCfgParams .Net == wire .STN , // whether or not server is using stn
1609-
1640+ "policy" : map [string ]interface {}{
1641+ "maxblocksize" : s .settings .Policy .ExcessiveBlockSize , // maximum block size
1642+ "maxminedblocksize" : s .settings .Policy .BlockMaxSize , // maximum mined block size
1643+ "maxstackmemoryusagepolicy" : s .settings .Policy .MaxStackMemoryUsagePolicy , // max stack memory usage policy
1644+ "maxstackmemoryusageconsensus" : s .settings .Policy .MaxStackMemoryUsageConsensus , // max stack memory usage consensus
1645+ },
16101646 }
16111647
16121648 if s .settings .RPC .CacheEnabled {
@@ -2694,3 +2730,61 @@ func handleGetchaintips(ctx context.Context, s *RPCServer, cmd interface{}, _ <-
26942730
26952731 return result , nil
26962732}
2733+
2734+ // generateBlocksAndReturnHashes is a shared helper method that generates blocks and returns their hashes.
2735+ // This method is used by both handleGenerate and handleGenerateToAddress to avoid code duplication.
2736+ //
2737+ // Parameters:
2738+ // - ctx: Context for cancellation and tracing
2739+ // - s: The RPC server instance providing access to service clients
2740+ // - count: Number of blocks to generate
2741+ // - address: Optional address for mining rewards (nil for generate command)
2742+ // - maxTries: Optional maximum number of attempts (nil for generate command)
2743+ //
2744+ // Returns:
2745+ // - []string: Array of block hashes of the generated blocks
2746+ // - error: Any error encountered during block generation
2747+ func (s * RPCServer ) generateBlocksAndReturnHashes (ctx context.Context , count int32 , address * string , maxTries * int32 ) ([]string , error ) {
2748+ // Get the current best block hash before generation
2749+ _ , bestBlockMeta , err := s .blockchainClient .GetBestBlockHeader (ctx )
2750+ if err != nil {
2751+ return nil , & bsvjson.RPCError {
2752+ Code : bsvjson .ErrRPCInternal .Code ,
2753+ Message : errors .NewServiceError ("RPC blockchain client" , err ).Error (),
2754+ }
2755+ }
2756+ startHeight := bestBlockMeta .Height
2757+
2758+ // Generate the blocks
2759+ err = s .blockAssemblyClient .GenerateBlocks (ctx , & blockassembly_api.GenerateBlocksRequest {
2760+ Count : count ,
2761+ Address : address ,
2762+ MaxTries : maxTries ,
2763+ })
2764+ if err != nil {
2765+ return nil , & bsvjson.RPCError {
2766+ Code : bsvjson .ErrRPCInternal .Code ,
2767+ Message : errors .NewServiceError ("RPC blockassembly client" , err ).Error (),
2768+ }
2769+ }
2770+
2771+ // Collect the block hashes of the generated blocks
2772+ // Note: There may be a brief delay between block generation and availability in blockchain client
2773+ var blockHashes []string
2774+ for i := int32 (1 ); i <= count ; i ++ {
2775+ targetHeight := startHeight + uint32 (i )
2776+
2777+ // Get the block at the target height
2778+ block , err := s .blockchainClient .GetBlockByHeight (ctx , targetHeight )
2779+ if err != nil {
2780+ return nil , & bsvjson.RPCError {
2781+ Code : bsvjson .ErrRPCInternal .Code ,
2782+ Message : errors .NewServiceError ("RPC blockchain client" , err ).Error (),
2783+ }
2784+ }
2785+
2786+ blockHashes = append (blockHashes , block .Header .Hash ().String ())
2787+ }
2788+
2789+ return blockHashes , nil
2790+ }
0 commit comments