1 为什么删了以后重启没办法挖矿,是因为创世块都被删了,你重新init一下就ok了。fullnode和lightnode工作原理很多不同。。,lightnode一般就是不挖矿的
你测试当然是都得测试。
2 怎么样整个区块的数据没办法恢复
只要让广播的区块无法通过验证就行了这样就硬分叉了,比如说 你试下篡改未来的区块,比如下一个挖到的块你把root改
,就会硬分叉。这个你有具体的日志信息?开个verbosity 5看下。还有一个点是 你是怎么篡改的
3 那如果改或者删除已经生成的数据呢?把大部分节点的Ldb都删掉,整个区块链的数据还是不会有影响吗? 我的篡改一般就是删除一些数据
这个真的不好说 因为如果你是把ldb文件打开删数据 因为本身是二进制文件,你随机删的话不知道删的是什么,。。一般是这样的话处理方法就是把数据库删掉重新init。你最好还是用专门的api来查数据库来针对性篡改比较好
4我是把源码一些api提取出来写的篡改脚本,一些现成的func可以直接用
4这个你要用的test.go话得把geth整个源码拷贝一份到你的GOROOT下。。。
package main
import (
"encoding/hex"
"fmt"
"math/big"
"github.com/ethereum/go-ethereum/ethdb"
// "github.com/ethereum/go-ethereum/trie"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/rlp"
)
func main() {
db, _ := ethdb.NewLDBDatabase("/Users/reimu/eth/chain/geth/chaindata", 128, 128)
defer db.Close()
fmt.Println(*db)
fmt.Println(db.Path())
testHash := common.HexToHash("1ff83e56e61474045300be48bfafa75f26b529f2b431ced50f9fb95179f552ef") // stateRoot from eth.getBlock()
StateDB, _ := state.New(testHash, db) // Result in a *StateDB
Addr := common.HexToAddress("67f1b0fde05a37ee895998e903e8242e63d036e0") // Contract Addr
// This key is the key of your target. It can be found by the result of ForEachStorage2()
key := common.Hash{168, 196, 212, 195, 62, 53, 105, 154, 143, 63, 17, 71, 81, 9, 0, 148, 77, 246, 224, 215, 137, 180, 15, 117, 116, 123, 19, 254, 236, 211, 171, 250}
// // StorageTrie()
// storageTrie := StateDB.StorageTrie(Addr)
// fmt.Println(storageTrie)
// // GetStateObject()
StateObject := StateDB.GetStateObject(Addr)
//StateObject.GetState(db, key)
// // ForEachStorage()
// count := 0
// callCount := func(key, value common.Hash) bool{
// count++
// fmt.Println("NO. ", count, ":")
// fmt.Println("key: ", key)
// fmt.Println("value: ", value,"\n")
// return true
// }
// StateObject.ForEachStorage(callCount)
// fmt.Println("Total: ", count)
StateObject.ForEachStorage2()
originalValue := "{\"Date\": \"2017-06-13 21:38:44\", "
// originalValueByte := []byte(originalValue)
// original := hex.EncodeToString(originalValueByte)
// originalByte := common.FromHex("0x" + original) // Decoded
// originalByteEncoded ,_ := rlp.EncodeToBytes(originalByte) //Encoded
// fmt.Println(originalByte)
// fmt.Println(common.BytesToHash(originalByteEncoded)) //Decoded
// fmt.Println(originalByteEncoded)
modifiedValue := "{\"Date\": \"2017-06-15 21:38:44\", "
modifiedValueByte := []byte(modifiedValue)
modified := hex.EncodeToString(modifiedValueByte)
modifiedByte := common.FromHex("0x" + modified)
modifiedByteEncoded, _ := rlp.EncodeToBytes(modifiedByte)
fmt.Println("Tampering:")
fmt.Println("OriginalData: ", originalValue)
fmt.Println("ModifiedValue:", modifiedValue)
fmt.Println("modifiedvalueRLPDecodeHex: ", "0x"+modified)
fmt.Println("modifiedvalueRLPDecodeByte: ", modifiedByte)
fmt.Println("modifiedvalueRLPEncodeByte: ", modifiedByteEncoded)
/* BytesToHash() is exactly the RLP Decoder, therefore modifiedByteEncoded == modifiedByte */
fmt.Println("HashValue sent to SetState(): ", common.BytesToHash(modifiedByteEncoded))
/* Normally currentBlock.Root() === common.ToHex(hash[:]) */
hash := StateDB.GetHash()
fmt.Println(hash)
fmt.Println(common.ToHex(hash[:]))
currentBlockHash := core.GetHeadBlockHash(db)
currentBlockNumber := core.GetBlockNumber(db, currentBlockHash)
currentBlock := core.GetBlock(db, currentBlockHash, currentBlockNumber)
currentReceipts := core.GetBlockReceipts(db, currentBlockHash, currentBlockNumber)
tamperBlock := types.NewBlock(currentBlock.Header(), currentBlock.Transactions(), currentBlock.Uncles(), currentReceipts)
/* Tampering!!! */
(1) Change State
StateObject.SetState(db, key, common.BytesToHash(modifiedByteEncoded))
// StateObject.CommitTrie(db, db)
current_root := StateDB.IntermediateRoot(true)
fmt.Println(common.ToHex(current_root[:]))
root, err := StateDB.Commit(true)
if err == nil {
fmt.Println(root)
fmt.Println(common.ToHex(root[:]))
}
// hash2 := StateDB.GetHash()
// fmt.Println(hash2)
// fmt.Println(common.ToHex(hash2[:]))
(2) Change Block
tamperBlock.HeaderReal().Root.Set(root)
// //tamperBlock.TxHash()
// //tamperBlock.UncleHash()
// //tamperBlock.ReceiptHash()
aa := tamperBlock.Root()
bb := tamperBlock.Hash()
fmt.Println(common.ToHex(aa[:]))
fmt.Println(common.ToHex(bb[:]))
(3) Set the TotalDifficulty
tdOriginal := big.NewInt(1456846644) // totalDfficulty from eth.getBlock()
TD := new(big.Int).Add(tdOriginal, tamperBlock.Difficulty())
(4) Delete the current Block
core.DeleteBlock(db, currentBlockHash, currentBlockNumber)
core.DeleteCanonicalHash(db, currentBlockNumber)
core.DeleteTransaction(db, currentBlockHash)
(5) Add the tampered Block
if err := core.WriteBlock(db, tamperBlock); err != nil {
fmt.Println("failed to insert block number: %v", err)
}
if err := core.WriteCanonicalHash(db, tamperBlock.Hash(), tamperBlock.NumberU64()); err != nil {
fmt.Println("failed to store number to hash mapping into database: %v", err)
}
// WriteTd is important. If you want to successfully hack, totalDifficulty should be large than that of the correct block.
if err := core.WriteTd(db, tamperBlock.Hash(), tamperBlock.NumberU64(), TD); err != nil {
fmt.Println("failed to store block total difficulty into database: %v", err)
}
if err := core.WriteHeadBlockHash(db, tamperBlock.Hash()); err != nil {
fmt.Println("failed to store last header's hash into database: %v", err)
}
if err := core.WriteHeadHeaderHash(db, tamperBlock.Hash()); err != nil {
fmt.Println("failed to store last block's hash into database: %v", err)
}
if err := core.WriteHeadFastBlockHash(db, tamperBlock.Hash()); err != nil {
fmt.Println("failed to store last fast block's hash into database: %v", err)
}
if err := core.WriteBlockReceipts(db, tamperBlock.Hash(), tamperBlock.NumberU64(), currentReceipts); err != nil {
fmt.Println("error writing block receipts:", err)
}
if err := core.WriteTransactions(db, tamperBlock); err != nil {
fmt.Println("failed to store transactions into database:", err)
}
(5) Check
currentTamperBlockHash := core.GetHeadBlockHash(db)
currentTamperBlock := core.GetBlock(db, currentTamperBlockHash, currentBlockNumber)
a := currentTamperBlock.Root()
b := currentTamperBlock.Hash()
fmt.Println(common.ToHex(a[:]))
fmt.Println(common.ToHex(b[:]))
}
在拷贝的源码里
core/types/block.go的453行Hash(),comment out了第一个判断,并且395行加上了func (b *Block) HeaderReal() *Header { return b.header }
core/state/state_object.go最后添加
func (self *StateObject) ForEachStorage2() {
// When iterating over the storage check the cache first
//for h, value := range self.cachedStorage {
// cb(h, value)
//}
// test := []byte{160, 123, 34, 68, 97, 116, 101, 34, 58, 32, 34, 50, 48, 49, 55, 45, 48, 54, 45, 49, 51, 32, 50, 49, 58, 51, 56, 58, 52, 52, 34, 44, 32}
it := self.getTrie(self.db.db).Iterator()
for it.Next() {
// ignore cached values
var decodedValue []byte
key := self.trie.GetKey(it.Key)
keyHex := common.ToHex(key)
rlp.DecodeBytes(it.Value, &decodedValue)
values := common.ToHex(decodedValue)
valueAscII, err := hex.DecodeString(values[2:])
if err != nil {
panic(err)
}
// key2 := it.Key
fmt.Println("Hashkey sent to SetState(): ", common.BytesToHash(key))
fmt.Println("keyByte: ", key)
fmt.Println("itKey: ", it.Key)
// fmt.Println("hashKey: ", self.trie.HashKeyTest(test)) //This result is exactly the it.Key
fmt.Println("keyHex: ", keyHex)
fmt.Println("valueByteRLPEncoded: ", it.Value)
fmt.Println("HashValue sent to SetState(), which is the valueRLPdecodedByte: ", decodedValue) // The same as common.BytesToHash(it.Value)
fmt.Println("valueRLPdecodedHex: ", values)
fmt.Println("valueAscII: ", string(valueAscII), "\n")
// self.GetState(self.db.db, key)
//if _, ok := self.cachedStorage[key]; !ok {
// cb(key, common.BytesToHash(it.Value))
//}
}
}