I do not know if there is a good way of doing this but I have used a trick to detect block-breaking to replace them with water for an underwater map.
theThe trick uses the fact that java editionJava Edition has three different types of air blocks air: blocks_air, cave_air and void_air. (these are used for terrain generation) when. When you break a block it always gets replaced with the normal air. so iSo I used a fill command executed around the player every tick to replace the normal air with water. thenThen if I wanted to have air I used cave_air which would not get replaced.
inIn your case you could replace the blocks with cave air instead of water then you can probably store the success of that fill function to a scoreboard to see if a block is broken.
noteNote that this would mean you need to convert the air to cave_air in the first place. youYou can probably do that by having like a hollow cube around the player bigger than its reach where you replace the air with cave_air.
thisThis will tell you when a block is broken. notNot what block, so you would have to keep track of what block a player is looking at at all times.