Modify the length of the Ethereum address

    The length of the Ethereum address is now 20 bytes and 160 bits, expressed in hexadecimal such as 0x4e4dd38E148c758e5a4f55035f0A0Ee6BCD5B8Bd. Address is the most basic module of Ethereum. All transfers and smart contracts on Ethereum need to deal with addresses. Why modify the address length of Ethereum? Modifying the address length can enhance security. The length of the public chain is 20 bytes. If the length of the private chain built by yourself is different from that of the public chain, for example, it is changed to 24 bytes, so that even if a hacker attacks, their transfer will not be successful. In this way, the private chain and the public chain are completely isolated.

    Address types are defined in common/types.go,

// Address represents the 20 byte address of an Ethereum account.

type Address [AddressLength]byte

The AddressLength definition is also in this file:

const (
	HashLength    = 32
	AddressLength = 20
)

Change AddressLength to 24.

After compiling and running,


New account:


Counting, this account has 48 bits, which is exactly 24 bytes, which proves that the change was successful. Is not it simple? But don't get too excited, run the command again:


The web3.js file reported an invalid address error. Open go-ethereum's internal/jsre/deps/web3.js file, line 3930 is:


The error is reported here, check the isAddress function:


It is found that a regular expression is used to judge the address here, if (/^(0x)?[0-9a-f]{40}$/.test(address) || /^(0x)?[0-9A-F] The expression {40}$/.test(address) is to judge that the length of the address is 40, and change them to 48. Search this file and change the 40 related to the address to 48. Including isStrictAddress, isAddress, isChecksumAddress and toAddress these four functions.

    After the modification, run the program again, and execute the balance query command or report the same invalid address error. What is happening? It turns out that the js files in go need to be compiled into go files before they can be used. Use the go-bindata tool to compile js files into go files. First install the go-bindata tool with the command:

go get -u github.com/jteeuwen/go-bindata/...

Then add the directory where the go-bindata tool file is located to the environment variable. Then go to the directory where the web3.js file is located:

cd go-ethereum/internal/jsre/deps

You can see that there are two js files in this directory, bignumber.js and web3.js, and two go files, bindata.go and deps.go,

Excuting an order:

go-bindata -nometadata -pkg deps -o bindata.go bignumber.js web3.js

Will repackage to generate bindata.go. At this time, compile and generate the geth client, and then query the balance after startup, and find that there is no problem. But there is a problem when transferring money:


It is obvious that the eth.accounts[0] account has 1e28 money, how to transfer an Ethereum (1e18) but the balance is insufficient? Add print information to the function validateTx of tx_pool.go that validates transactions

func (pool *TxPool) validateTx(tx *types.Transaction, local bool) error {
	// Heuristic limit, reject transactions over 32KB to prevent DOS attacks
	log.Info("txSize:","size",tx.Size())
	if tx.Size() > 320*1024 {
		return ErrOversizedData
	}
	// Transactions can't be negative. This may never happen using RLP decoded
	// transactions but may occur if you create a transaction using the RPC.
	if tx.Value().Sign() < 0 {
		return ErrNegativeValue
	}
	// Ensure the transaction doesn't exceed the current block limit gas.
	if pool.currentMaxGas < tx.Gas() {
		return ErrGasLimit
	}
	// Make sure the transaction is signed properly
	from, err := types.Sender(pool.signer, tx)
	if err != nil {
		return ErrInvalidSender
	}
	log.Info("from addr:","addr",from) //Add this print information
	// Drop non-local transactions under our own minimal accepted gas price
	local = local || pool.locals.contains(from) // account may be local even if the transaction arrived from the network
	if !local && pool.gasPrice.Cmp(tx.GasPrice()) > 0 {
		return ErrUnderpriced
	}
	// Ensure the transaction adheres to nonce ordering
	if pool.currentState.GetNonce(from) > tx.Nonce() {
		return ErrNonceTooLow
	}
	// Transactor should have enough funds to cover the costs
	// cost == V + GP * GL
	if pool.currentState.GetBalance(from).Cmp(tx.Cost()) < 0 {
		return ErrInsufficientFunds
	}
	intrGas, err := IntrinsicGas(tx.Data(), tx.To() == nil, pool.homestead)
	if err != nil {
		return err
	}

	if tx.Gas() < intrGas {
		return ErrIntrinsicGas
	}
	return nil
}
Continue the transfer process above:


See the problem? The original transferor account is eth.accounts [0], address 0x0000000058a2d5f72f3fd0769cce05c10d06b8f4d28b2d06, and print out the transfer from the account is 0x58A2D5F72f3FD0769cce05c10d06B8F4D28B2D0600000000, from and eth.accounts [0] turned out to be inconsistent (supposed to be the same), is removed from the back of the The part of 0 is exactly the same as the part of eth.accounts[0] with the leading 0 removed. This is a problem with shifting! The problem is with the function

from, err := types.Sender(pool.signer, tx)

The function of this function is to recover the outgoing account address from the transaction signature. Trace this function, which is implemented in the recoverPlain of transaction_signing.go:

func recoverPlain(sighash common.Hash, R, S, Vb *big.Int, homestead bool) (common.Address, error) {
	if Vb.BitLen() > 8 {
		return common.Address{}, ErrInvalidSig
	}
	V := byte(Vb.Uint64() - 27)
	if !crypto.ValidateSignatureValues(V, R, S, homestead) {
		return common.Address{}, ErrInvalidSig
	}
	// encode the snature in uncompressed format
	r, s := R.Bytes(), S.Bytes()
	sig: = make ([] bytes, 65)
	copy(sig[32-len(r):32], r)
	copy (sig [64-len (s): 64], s)
	sig [64] = V
	// recover the public key from the snature
	pub, err := crypto.Ecrecover(sighash[:], sig)
	if err != nil {
		return common.Address{}, err
	}
	if len (pub) == 0 || pub [0]! = 4 {
		return common.Address{}, errors.New("invalid public key")
	}
	var addr common.Address
	copy(addr[:], crypto.Keccak256(pub[1:])[12:])
	return addr, nil
}

Note that the penultimate line is the assignment statement of addr. The output result of crypto.Keccak256(pub[1:]) is 32 bytes, so crypto.Keccak256(pub[1:])[12:] is 20 bytes. It is the length of the eth.accounts[0] address after removing 0. addr is 24 bytes, the default addr in the source code is 20 bytes, so the copy is copy(addr[:], crypto.Keccak256(pub[1:])[12:]), now the address is changed to 24 bytes , so it needs to be changed to copy(addr[4:], crypto.Keccak256(pub[1:])[12:]).

    After modification, compile and run, this time you can transfer successfully. The printed from address is also consistent with eth.accounts[0].

    When using truffle to publish a smart contract, the address error will be prompted. Change the address length from 40 to 48 in the cli.bundled.js file in the truffle program directory (in /usr/lib/node_modules/truffle/build). . Mainly isStrictAddress(), isAddress(), isChecksumAddress(), toAddress() and other 4 functions.



Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=326010075&siteId=291194637