Ethereum

这篇具有很好参考价值的文章主要介绍了Ethereum。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

区块链版本

  • 区块链1.0,以BTC公链为代表:不具备只能合约功能,是一条支持电子货币转账的完整区块链。
  • 区块链2.0,以ETH公链为代表:具备智能合约功能,共识机制是PoW向PoS过去,但是目前共识机制还是使用PoW,但是此PoW算法经过改进,性能优于BTC的PoW。
  • 区块链3.0,以EOS公链为代表:性能高,大吞吐量,支持智能合约功能,共识算法是DPoS,目前向BFT-DPoW发展。

ETH框架

ETH的技术栈分为6个层级:分别为应用层,网络层,合约层,共识层,激励层和数据层

  • 应用层:主要是以ETH公链衍生出来的应用,如:DApp,Geth控制台,Web3.js,钱包等。
  • 网络层:主要是以ETH的P2P通讯和RPC(远程过程调用)接口服务。
  • 合约层:主要是基于EVM的智能合约模块开发的智能合约。
  • 共识层:主要是节点使用的共识机制。
  • 激励层:主要提现在对minter的奖励。
  • 数据层:用于整体的数据管理,包含但不限于区块数据,交易数据,事件数据和levelDB存储技术模块等。
    Ethereum
  • DApp应用通过web3.js,web3.py或者其他SDK的以太坊接口访问代码,来访问以太坊的RPC接口或者对应的数据。接口细分可分智能合约相关接口和区块相关接口。
  • Whisper是P2P通讯模块中的协议,通讯消息都是经过它转发,所有转发的消息都经过加密传输。
  • Swarm是ETH实现类似于IPFS的分布式文件存储系统,在P2P模块中结合Whisper协议使用。
  • HttpClient是Http服务请求方法的实现模块。
  • Crypto是ETH的加密模块,内部包含SHA3、SECP256k1等加密算法。
  • RLP是ETH所使用的一种数据编码方式,包含数据序列化和反序列化,除了常见的编码方式外,还包含了base16,base32,base64等。
  • Solidity是ETH的高级计算机编程语言,由EVM载入字节码运行。
  • LevelDB是ETH所使用的键值对数据库,区块和交易数据都采用该数据库存储。在ETH中,作为key的一般是数据的hash,而value则是数据的RLP编码。
  • Logger是日志模块,主要分为两类:一类是智能合约的Event日志,这类日志被存储到区块链中,可以通过调用相关的RPC接口获取;另一类是代码级别的运行日志,这类日志会被保存到本地的日志文件。

DApp(Decentralized Application)介绍

顾名思义:去中心化应用。
一般应用都是C/S(Client/Server,即客户端/服务端)模式,多个C,一个S,但是传统的分布式应用是多个C,多个S,但是多个S公用一个数据库(可能有多个数据库,但是数据库的关系是主从关系,整体可以理解为一个数据库,这里提现还是中心化的),去中心化应用和传统的分布式应用相同的地方还是多个S多个C,但是不同的是S对应的数据库,相互独立,互不干扰(即可以理解为每个节点都有它自己的数据库)。

ETH的DApp

ETH具备图灵完备,一般在ETH上部署智能合约,然后通过web3.js,web3.py或者其他SDK的以太坊接口访问链上的智能合约,最后得到输出。
DApp一般含有多个角色,每个角色各司其职。

  • 智能合约应用,负责链上的数据处理。
  • 中继服务负责接收用户的请求和访问链上的智能合约应用,再将链上输出的数据结果返回给用户。(举个例子,开发一个翻译APP的中继服务,用户输入单词,中继服务接收用户输入的单词,然后把用户输入的单词,通过API发送给翻译平台,翻译平台翻译该单词,并给回结果到中继服务器,中继服务器再把该结果返回给用户)

区块的组成

以下是ETH源码对区块结构体(Block)的定义

// Header表示ETH区块链中的区块报头
type Header struct {
	// 父区块的哈希值
	ParentHash  common.Hash    `json:"parentHash"       gencodec:"required"`
	// 叔块hash
	UncleHash   common.Hash    `json:"sha3Uncles"       gencodec:"required"`
	// 挖出这个块的minter地址,因为mint出块所奖励的ETH就会发放到这个地址。
	Coinbase    common.Address `json:"miner"`
	// 全局状态MPT树的根哈希,这个全局状态树包含了以太坊网络中每一个账户的一组键值对,stateDB的RLP编码后的哈希值
	Root        common.Hash    `json:"stateRoot"        gencodec:"required"`
	// 交易MPT树的根哈希,由本区块所有交易的交易哈希算出
	TxHash      common.Hash    `json:"transactionsRoot" gencodec:"required"`
	// 收据MPT树的哈希
	ReceiptHash common.Hash    `json:"receiptsRoot"     gencodec:"required"`
	// 布隆过滤器,快速定位日志是否在这个区块中。
	Bloom       Bloom          `json:"logsBloom"        gencodec:"required"`
	// 当前工作量证明(Pow)算法的复杂度。
	Difficulty  *big.Int       `json:"difficulty"       gencodec:"required"`
	// 区块号
	Number      *big.Int       `json:"number"           gencodec:"required"`
	// 每个区块Gas的消耗上限。
	GasLimit    uint64         `json:"gasLimit"         gencodec:"required"`
	// 当前区块所有交易使用的Gas之和。
	GasUsed     uint64         `json:"gasUsed"          gencodec:"required"`
	// 区块产生出来的Unix时间戳
	Time        uint64         `json:"timestamp"        gencodec:"required"`
	// 该变量用于为当前区块的建造者保留的附属信息
	Extra       []byte         `json:"extraData"        gencodec:"required"`
	// 区块产生出来的Unix时间戳
	MixDigest   common.Hash    `json:"mixHash"`
	// mint找到的满足条件的值。
	Nonce       BlockNonce     `json:"nonce"`
	// BaseFee是由EIP-1559添加的,在遗留头文件中被忽略
	BaseFee *big.Int `json:"baseFeePerGas" rlp:"optional"`
	/*
	TODO (MariusVanDerWijden)需要时添加此字段
	// Random是在合并过程中添加的,包含BeaconState随机性
	Random common.Hash `json:"random" rlp:"optional"`
	*/
}

// Block表示以太坊区块链中的一个完整的区块。
type Block struct {
	// block的header指向的是一个的结构体,其中带有该block的所有属性信息
	header       *Header
	// 叔块block的数组
	uncles       []*Header
	// 当前该区块所有打包的交易记录
	transactions Transactions
	// 缓存,应该是该区块的的hash及区块大小
	hash atomic.Value
	size atomic.Value

	// total difficulty,当前区块总共的难度值=前一个区块的td+当前区块header中的difficulty。
	td *big.Int
	// 区块被接受的时间
	ReceivedAt   time.Time
	// 记录区块是从哪个P2P网络传过来的
	ReceivedFrom interface{}
}

ETH Address

在ETH中,每个账户,其中包含用户账户和智能合约账户,都是一个字符长度为42的十六进制地址值,该值作为唯一标识自己的地址值,通过ETH的RPC接口可以查询到该地址的相关信息。
地址值规则如下3点:

  1. 0x开头。
  2. 除0x这两个字符外,剩下的部分(即40个字符)必须由数字(0-9)和字母(a-f)组成,其中,不分大小写。
  3. 整体是一个十六进制字符串。
地址的作用
  1. 唯一标识一个账户或合约
  2. 作为标识,用于查询地址账户信息
  3. 进行ETH交易时,充当交易双方的唯一标识
地址的生成

地址又分为非合约地址和合约地址(又称外部地址和内部地址),生成地址的方式不同,具体如下。
非合约地址(外部地址)的生成流程

  1. 随机产生一个私钥(大整数),32个字节
  2. 计算得到的私钥在ECDSA-secp256k1椭圆曲线上对应的公钥。
  3. 对公钥进行SHA3计算,得到一个哈希值,取这个哈希值的后20个字节来作为非合约地址(即外部账户地址)。

合约地址(内部地址)的生成流程

  1. 使用RLP算法将(合约创建者地址+当前创建合约交易的序列号Nonce)进行序列化。
  2. 使用Keccak256将步骤1的序列化数据进行哈希运算,得出一个哈希值。
  3. 取第(2)步的哈希值的前12字节之后的所有字节生成地址,即后20个字节

TIP

  • 合约地址和椭圆曲线加密无关,因为合约地址是基于用户地址和交易序列号的,所以不会出现雷同情况。
  • 私钥是通过伪随机算法(PRNG)产生的,是一个256位(32个字节)的二进制数。 2 256 2 ^ {256} 2256非常大,能够保证在一个十分的安全范围内。

Header中Nonce的作用

区块Header中是的Nonce主要用于PoW共识情况下的mint,是一个随机数,minter在不断尝试Nonce,直到找到合适的Nonce即可出块。

燃料费(Gas)

计算公式

Gas = GasUsed * GasPrice
其中:
	GasPrice:单价
	GasUsed:计算数量
	GasLimit:基础量

GasLimit有两个基础量:
	1.创建智能合约的基础量:53000
	2.非创建智能合约的基础量:21000

在交易函数中设置的GasLimit比基础量小时,就会导致交易失败。这也是之前在部署智能合约的时候出现Gas估计错误的原因。

计算的方式按照ETH设置的规则计算
	1.0字节的收费为4,没发现一个0字节,基础量累加4
	2.0字节的收费68,每发现一个非0字节,基础量累加68

ETH的EVM计算Gas的源码
更加具体,to read yellowpaper,please!

// TransitionDb将通过应用当前消息并返回带有以下字段的evm执行结果来转换状态。
// - used gas:
//      总使用的gas(包括已退还的用气量)
// - returndata:
//      从evm返回的数据
// - concrete execution error:
// 		各种**EVM**错误终止执行,
// 		例如:ErrOutOfGas, ErrExecutionReverted
//
// 但是,如果遇到任何共识问题,直接返回错误
// 无evm执行结果。
func (st *StateTransition) TransitionDb() (*ExecutionResult, error) {
	//首先检查此消息是否满足之前的所有共识规则
	//应用消息。规则包括这些条款
	// 1。消息调用者的nonce是正确的
	// 2。来电者有足够余款支付交易费用(汽油限价*汽油价格)
	// 3。所需的天然气量在该区块内可用
	// 4。购买的汽油足够支付内在使用量
	// 5。计算内禀气体时无溢出现象
	// 6。来电者有足够的余额来支付**最高**呼叫的资产转移

	// 检查条款1-3,如果一切正确,就 buy gas
	if err := st.preCheck(); err != nil {
		return nil, err
	}

	if st.evm.Config.Debug {
		st.evm.Config.Tracer.CaptureTxStart(st.initialGas)
		defer func() {
			st.evm.Config.Tracer.CaptureTxEnd(st.gas)
		}()
	}

	var (
		msg              = st.msg
		sender           = vm.AccountRef(msg.From())
		rules            = st.evm.ChainConfig().Rules(st.evm.Context.BlockNumber, st.evm.Context.Random != nil)
		contractCreation = msg.To() == nil
	)

	// 检查条款4-5,如果一切正确,减去 内部的 gas
	gas, err := IntrinsicGas(st.data, st.msg.AccessList(), contractCreation, rules.IsHomestead, rules.IsIstanbul)
	if err != nil {
		return nil, err
	}
	if st.gas < gas {
		return nil, fmt.Errorf("%w: have %d, want %d", ErrIntrinsicGas, st.gas, gas)
	}
	st.gas -= gas

	// 检查条款6
	if msg.Value().Sign() > 0 && !st.evm.Context.CanTransfer(st.state, msg.From(), msg.Value()) {
		return nil, fmt.Errorf("%w: address %v", ErrInsufficientFundsForTransfer, msg.From().Hex())
	}

	// 设置初始访问列表。
	if rules.IsBerlin {
		st.state.PrepareAccessList(msg.From(), msg.To(), vm.ActivePrecompiles(rules), msg.AccessList())
	}
	var (
		ret   []byte
		vmerr error // vm错误不影响共识,因此不分配给err
	)
	if contractCreation {
		ret, _, st.gas, vmerr = st.evm.Create(sender, st.data, st.gas, st.value)
	} else {
		// 为下一个事务增加nonce
		st.state.SetNonce(msg.From(), st.state.GetNonce(sender.Address())+1)
		ret, st.gas, vmerr = st.evm.Call(sender, st.to(), st.data, st.gas, st.value)
	}

	if !rules.IsLondon {
		// EIP-3529之前:退款上限为gasUsed / 2
		st.refundGas(params.RefundQuotient)
	} else {
		// EIP-3529之后:退款上限为gasUsed / 5
		st.refundGas(params.RefundQuotientEIP3529)
	}
	effectiveTip := st.gasPrice
	if rules.IsLondon {
		effectiveTip = cmath.BigMin(st.gasTipCap, new(big.Int).Sub(st.gasFeeCap, st.evm.Context.BaseFee))
	}
	st.state.AddBalance(st.evm.Context.Coinbase, new(big.Int).Mul(new(big.Int).SetUint64(st.gasUsed()), effectiveTip))

	return &ExecutionResult{
		UsedGas:    st.gasUsed(),
		Err:        vmerr,
		ReturnData: ret,
	}, nil
}
叔块奖励规则
激励计算共识
reward = (uncleNumber + 8 - headerNumber) * blockReward / 8

-- uncleNumber: 叔块的高度,即区块号
-- headerNumber: 当前正在打包的区块高度
-- blockReward: mint出区块时,给minter的基础奖励,目前是 3 ETH
-- 满足关系: headerNumber - 6 < uncleNumber < headerNumber - 1
间隔层数 报酬比例 报酬(ETH)
1 7/8 2.625
2 6/8 2.25
3 5/8 1.875
4 4/8 1.5
5 3/8 1.125
6 2/8 0.75
Mint Reward

ETH mint 出的区块有三种:

  1. 普通的成功进入主链的区块,有ETH奖励
  2. 被主链区块打包的叔块的分叉区块(叔块),有ETH奖励
  3. 孤块,没有任何奖励

普通的成功进入主链的区块的奖励构成:共 3 部分

  1. 固定的基础奖励,Block Reward
  2. mint的区块打包了的所有交易的gas总和,即Header结构体的GasUsed字段的值
  3. 当前区块打包叔块的奖励,一个区块最多只能打包 2 个叔块。奖励计算公式:reward = N * Block Reward / 32。N即是当前区块打包了叔块的数量值。

看一个例子:
Ethereum

默克尔数

ETH区块的Herder结构的Root,Txhash,ReceiptHash代表的都是ETH默克尔前缀树(MPT)的根节点哈希值(Hash)。
默克尔树(也称作哈希树),它满足树的数据结构特点。默克尔树满足下面的条件:

  • 树的数据结构,包含不局限于二叉树,也可以是多叉树,具有树结构的全部特点。
  • 基础数据不是固定的,节点所存储的数据值是具体的数据值经过哈希运算后所得到的哈希值。
  • 哈希的计算是从下往上逐层进行的,就是说每个中间节点根据相邻的两个叶子节点组合计算得出,跟节点的哈希值根据其左右孩子节点组合计算得出。
  • 最底层的节点包含基础的数据
ETH钱包地址存储余额的方式

ETH区块Header结构体中,Root变量的真实含义是ETH区块账户MPT树根节点的哈希值,区块账户MPT树中每个叶子节点的Key中存放的是ETH钱包的地址值,叶子节点的Value对应的是ETH的状态存储对象stateObject。stateObject中包含stateAccount对象,在stateAccount对象中有一个指针变量Balance,指向ETH存放余额的内存地址。
ETH源码定义的stateObject和stateAccount结构体如下:

// stateObject表示一个正在被修改的ETH账户。
// 使用模式如下:
// 首先你需要获得一个state_object。
// 帐户值可以通过对象访问和修改。
// 最后,调用CommitTrie将修改后的存储trie写入数据库。
type stateObject struct {
	address  common.Address  
	addrHash common.Hash // ETH钱包地址的hash值
	data     types.StateAccount // StateAccount对象
	db       *StateDB

	// 数据库错误。
	// stateObject会被共识算法的核心和VM使用,在这些代码内部无法处理数据库级别的错误。 
	// 在数据库读取期间发生的任何错误都会在这里被存储,最终将由StateDB.Commit返回。
	dbErr error

	// 写缓存
	trie Trie // 用户的存储trie ,在第一次访问的时候变得非空
	code Code // 合约字节码,当代码被加载的时候被设置

	originStorage  Storage // 要重复数据删除的原始条目的存储缓存会重写,对每个事务进行重置
	pendingStorage Storage // 在整个块的末尾需要刷新到磁盘的存储条目
	dirtyStorage   Storage // 在当前事务执行中被修改的存储项
	fakeStorage    Storage // 由调用者为调试而构造的伪存储。

	// 缓存的标记
	// 当一个对象被标记为自杀时,它将在状态转换的“更新”阶段从try中删除。
	dirtyCode bool // 如果更新了代码,则为true
	suicided  bool
	deleted   bool
}

// StateAccount是ETH账户的共识表示。
// 这些对象存储在主帐户trie中。
type StateAccount struct {
	Nonce    uint64
	// 如果账户是用户钱包账户,Nonce表示的是该账户发出当前交易时的交易序列号
	// 如果账户是智能合约账户,Nonce表示的是此账户创建的合约序列号
	Balance  *big.Int
	// 该账户目前存放ETH余额的内存地址,TIP:ETH Coin
	Root     common.Hash 
	// 存储树的默克尔根的哈希值
	CodeHash []byte
	// 如果账户是用户钱包账户,该值为空
	// 如果是智能合约账户,该值对应于当前初始发布智能合约的十六进制哈希值
}
余额的查询顺序

账户数据会持久化保存到<k,v>数据库(键值对数据库)中,但是查询余额时并不是直接去查<k,v>数据库,这是因为ETH钱包地址中Token的余额查询上设置了三层缓存机制。
在stateObject结构体中,有一个StateDB类型的db指针对象,该db指针对象就是存储了基于内存的缓存Map。其ETH源码的StateDB结构体定义如下:

// 以太坊协议中的StateDB结构用于存储merkle try中的任何内容。
// statedb负责缓存和存储嵌套状态。
// 它是用于检索的通用查询接口:
// * 合约
// * 账户
type StateDB struct {
	db           Database
	prefetcher   *triePrefetcher
	originalRoot common.Hash // 状态前根,在做出任何改变之前
	trie         Trie
	hasher       crypto.KeccakState

	snaps         *snapshot.Tree
	snap          snapshot.Snapshot
	snapDestructs map[common.Hash]struct{}
	snapAccounts  map[common.Hash][]byte
	snapStorage   map[common.Hash]map[common.Hash][]byte

	// 这个映射保存着“活动”对象,它将在处理状态转换时被修改。
	stateObjects        map[common.Address]*stateObject
	stateObjectsPending map[common.Address]struct{} // 状态对象已完成但尚未写入 trie
	stateObjectsDirty   map[common.Address]struct{} // 状态对象在当前执行中被修改

	// DB error.
	// 状态对象被共识核心和VM使用,它们无法处理数据库级别的错误。
	// 在读取数据库期间发生的任何错误都将被存储在这里,
	// 并最终由StateDB.Commit返回。
	dbErr error

	// 这个退还计数器, 也用于状态转换。
	refund uint64

	thash   common.Hash
	txIndex int
	logs    map[common.Hash][]*types.Log
	logSize uint

	preimages map[common.Hash][]byte

	// 外加访问列表
	accessList *accessList

	// 日志状态修改.
	// 这是Snapshot和RevertToSnapshot的主干。
	journal        *journal
	validRevisions []revision
	nextRevisionId int

	// 在执行期间为调试目的收集的度量
	AccountReads         time.Duration
	AccountHashes        time.Duration
	AccountUpdates       time.Duration
	AccountCommits       time.Duration
	StorageReads         time.Duration
	StorageHashes        time.Duration
	StorageUpdates       time.Duration
	StorageCommits       time.Duration
	SnapshotAccountReads time.Duration
	SnapshotStorageReads time.Duration
	SnapshotCommits      time.Duration

	AccountUpdated int
	StorageUpdated int
	AccountDeleted int
	StorageDeleted int
}

余额的查找顺序如下:

  1. 第一级查找基于内存中的stateObject对象,这里保留了近期比较活跃的账号信息
  2. 第二级查找基于内存中的trie树
  3. 第三级查找基于leveldb,即<k,v>数据库层

第一、二级查找都是基于内存,第二级的Trie提现在diamagnetic上的一个接口,在stateObject中,trie变量最终是一棵MPT树,它被用于在检验某个钱包地址的stateObject数据是否真的存在于某个区块中,其验证方式就是验证默克尔树的数据校验的方式。文章来源地址https://www.toymoban.com/news/detail-514849.html

到了这里,关于Ethereum的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • GENESIS公链将打破不同区块链孤岛效应

    如今经济发展迅猛,用户交易、数字货币需求及原生资产的第三方跨链需求日益增长,交易安全、用户隐私等问题也备受瞩目。 自从Web2.0时代人们可以交易信息和价值以来,伴随使用第三方带来滥用用户信息和隐私等他问题,除了暂时便利还有高昂的中介成本。 而现在迎来

    2024年02月16日
    浏览(52)
  • 区块链开发团队,公链开发才是主战场

    在区块链技术开发公司不断完善的当下,很多企业都想加入进来。有远见的人永远能嗅到区块链未来市场的发展趋向,以区块链技术开发实体企业应用,在空白的市场里拥有无限开发潜力!而创业者要做的就是快人一步,才能夺得市场先机!我们团队作为一家专业的区块链公

    2024年02月16日
    浏览(36)
  • 区块链模块化的大胆尝试,解读公链Celestia

    作为以链游为主的社区,暴躁兔也会时常关注加密行业的其他赛道和方向。对于目前市场而言,公链的机会与红利仍然存在,且相对而言,技术创新较多,同时资本也比较喜欢这样的赛道。今天为大家讲解的是Cosmos生态的项目Celestia,也欢迎大家持续关注我们。 Celestia简介

    2024年02月08日
    浏览(45)
  • 你真的了解区块链吗?公链侧链,私有链联盟链概述

    导读:目前,区块链主要分为三类——公有链、私有链和联盟链。 **公有链:**对所有人开放,任何人都可以参与。 **联盟链:**对特定的组织团体开放。 **私有链:**对单独的个人或实体开放。 定义 公有链是指全世界任何人都可读取的、任何人都能发送交易且交易能获得有

    2024年04月22日
    浏览(50)
  • 项目调研丨多区块并行处理公链 Transformers 研究报告

    目录 一、项目简介 二、项目愿景 三、特色和优势 (1)速度 (2)安全 (3)可扩展性 (4)高度定制 (5)不可篡改 (6)所有数据公开透明 (7)支持智能合约 四、发展历史 五、团队背景 六、融资信息 七、项目架构 (1)网络 (2)共识算法 (3)DAG (4)同步化 (5)交易

    2024年02月10日
    浏览(43)
  • J9数字论:如何理解区块链中的公链,私链,侧链,联盟链

    区块链简而言之,就是一个分散式的记账本,有着点对点交易查询,公正,透明,可追溯,不可篡改,去中心化的特点。 区块链在大类上被分为公共区块链(公链),联盟区块链和私有区块链,TVL和用户量最大的公链当属以太坊。而除以太坊以外,其他公链在自身定位分类或

    2024年02月12日
    浏览(44)
  • 区块链合约安全系列(三):如何认识及预防公链合约中的自毁攻击

    id:BSN_2021 公众号:BSN 研习社 作者:红枣科技张雪良 背景:由于公链环境下所有的信息都是共享的,智能合约相当于是完全透明化,任何人都可以调用,外加一些利益的驱动,导致引发了很多hacker的攻击。其中self destruct攻击也是常见的攻击方式之一。 目标:将目标合约瘫痪

    2024年02月01日
    浏览(40)
  • Going Global with Blockchain Technology—— 以区块链为代表的全球变革趋

    作者:禅与计算机程序设计艺术 随着移动互联网、物联网、云计算等新兴技术的蓬勃发展,各行各业都将全力应对复杂多变的社会、经济、政治、法律、组织结构甚至生命健康方面的挑战。世界经济一体化进程加快了数字经济的发展速度,全球贸易额也在扩大。智能设备、互

    2024年02月08日
    浏览(42)
  • 全球公链进展| Shibarium已上线;opBNB测试网PreContract硬分叉;Sui 主网 V1.7.1 版本

    以太坊最新一次核心开发者执行会议:讨论 Devnet 8 更新、ElP-4788、Holesky 测试网等 以太坊核心开发者 Tim Beiko 总结最新一次以太坊核心开发者执行会议(ACDE),讨论内容包括 Devnet 8 更新、ElP-4788、Holesky 测试网、 EIP 编辑方面的更新以及新提出的 EIP-7212(secp256r1 预编译)。下

    2024年02月11日
    浏览(45)
  • 解决Spring Initializr只能创建为Java 17版本以上的问题

      目前我们发现使用IntelliJ IDEA通过Spring Initializr创建创建Spring Boot项目只能创建Java 17版本以上,但我们常用的还是Java 8版本,那么该如何解决呢?   Spring Initializr是Spring官方提供的一个用于初始化Spring Boot项目的工具。它可以帮助开发人员快速创建一个基于Spring Boot的项目

    2024年02月04日
    浏览(55)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包